Appendix B.
MuP21 eForth Version 2.08
The first batch of MuP21 chips were packaged by Orbit
Semiconductor. Actually, Orbit sent
the wafers to Phillipines for packaging, and charges a fairly high price for
the service. At the time, the
concerns was to get the chips manufactured by one vendor to minimize the risks
in the manufacturing processed. In
one batch, Orbit produced 10 wafers and only 2 were diced and packaged into
40-pin DIP packeges. The chips
worked, but not as good as the prototypes.
One problem was that the A! instruction does not function properly in
slots 1, 2 and 3. The best we could
deduce from this strange behavior was that in the plastic DIP packages, the
bonding wires are surounded by epoxy and the wire inductance is increased and
thus slows down the data stack access time. When A! is executed in slot 2, 3, or 4,
the data in the T register have not yet stablized and erroreous data is copied
into the A register.
The 44-pin PLCC package is much more attractive
because it is about 30% of the 40-pin DIP package, and the bounding wires are
shorter. We decided to have the
rest of the diced packaged in this form.
Searching around in the
Last Christmas I want back to
This Appendix summarizes the work with MuP21H on this
new board. The pin-out diagram of
MuP21H is shown in Appendix B1, and the schematics of the new PC board is
included in B2. The complete MuP21
eForth system source code is included in B4-B10, with the README file in
B3. Appendix B thus contains the
complete definition of a MuP21H system and is valuable for those who will want
to implement their own systems using the PLCC packaged chips.
B1. MuP21H
Pinouts
B2. New PC Board
Layout
Bill of Materials
Item Amount Part# Price Comment
Jameco
DRAM SIMM 1 75177 184.95 1Mx36/70
EPROM 1 39669 5.95 M27C010/20
80C51 1 52370 3.75 UART
CD4040 1 12950 0.59 Freq.
divider
Max233 1 106163 5.75
14.3M Clock 1 108652 3.29 For
video
1.84M Clock 1 27879 3.29 For
UART
7805T 1 51262 0.49 Regulator
Power Brick 1 100853 5.75 9V/200mA
Tatalum Cap 2 94094 0.47 22u/16V
Resistor 100K 1 29997
Resistor 82 1 60302
Reset Switch 1 119790 0.69
PLCC Socket 1 71618 1.49 MuP21H
SIMM Socket 1 72426 2.25 DRAM
DIP 40-pin 1 41136 1.19 52C50
DIP 32-pin 1 105380 1.09 M27C010
DIP 20-pin 1 38623 0.79 Max233
DIP 14-pin 2 37169 0.59 Clocks
RCA Socket 1 112475 0.49
DIN5 Socket 1 29399 0.69
DB9 Socket 1 104951 0.65
Mouser
Box 1 546-1598BBK 10.16
LED 1 351-2501 0.49
Capactor 10 58-UDW104M1 0.16 0.1uF
Offete
MuP21H 1 40.00
PCB 1
B3. ReadMe.seq
eForth
for Plastic MuP21 Chips
C.
H. Ting
Version
2.08 4/8/96
Files:
meta28.seq, ok28c.seq, hline27.seq, kernel28.seq, inner.seq
eForth28.seq
1. This version of eForth
is specifically designed for the new P21B5 PCB, which uses an 82C51 UART for
serial communication with the host PC.
2. P21B5 board hosts the
MuP21H in 44-pin PLCC package.
3. Words added to eForth
to display characters abd rectangles on TV:
tvAT ( x y -- ) Set
current location to (x,y). Top-left
(0,0), lower right (19,39).
tvEMIT ( char -- ) Display
char at current location. Move
current location to right.
tvCR ( -- ) Scroll
screen up by one line. Current location is at lower left corner
of the screen.
FG ( color -- ) Set foreground
color for charaters.
BG ( color -- ) Set
background color for characters.
RECTANGLE
( x y width height -- ) Draw a rectangle
with foreground
color.Width is on
4-pixel boundary.
RECT
( x1 x2 y1 y2 -- ) Draw
a rectangle using the 8x8 color pattern
stored in 300-30F.
SetColor ( color -- ) Init
array 300-30F to a single color for RECT.
SLOW ( -- ) Slow
down RS232 sampling to reduce video jitter.
FAST ( -- ) Increase
RS232 sampling rate for file downloading.
4. tvCR and tvEMIT form
the minimum word set to manage a scrolling screen character display. After tvCR, the screen is scrolled up
one line and the bottom line is cleared for character entry. tvAT is added for flexibility to address
the screen display randomly.
5. Color code is as
follows:
0 Black 8 Black
1 Dark blue 9 Light blue
2 Dark red A Light red
3 Dark brown B Yellow
4 Dark green C Light green
5 Dark cyan D Cyan
6 Dark magenta E Magenta
7 Gray F White
6. Only three baud rate
can be selected: 7200, 14.4K and 28.8K by jumpering to appropriate pins on the frequency divider CD4040. Master clock to CD4040 and 82C51 is
1.8432 MHz. 82C51 must be
programmed to run at x16 mode. The
prescaler divides input clock by 16 to run RxC and TxC.
7. A socket is provided to
connect to a standard AT keyboard as an alternate input device. However, this operation has not be
explored.
Version
2.07 11/24/95
Files:
meta27.seq, ok27c.seq, hline27.seq, kernel27.seq, inner.seq
eForth27.seq
Merge
rectangle code with eForth.
Add
newColor demo code.
Version
2.06 11/11/95
File
name changes: meta26.seq, ok26c.seq, okchar26.seq
I/O
is returned to 250ns slow mode to stablize the RS232 communications.
Use
74HC138, 74HC245, 74HC574 for input and output.
Use
a 1.8432 MHz clock in the place of 14.318 MHz clock. By slowing
down
the video clock input, the timing on RS232 port can be
maintained
accurately and the drift of baudrate is greatly reduced.
This
makes the serial communication with the host computer stable
and
usable.
Add
HOST.EXE. This is the host
terminal/file server adopted from
Lesson11
in The Forth Course by Richard Haskell.
To
download a file from PC to eForth in MuP21:
1. bring up HOST by
C:>HOST
2. Boot eForth
3. Press B or b on
host keyboard
4. Test eForth from
keyboard
5. Start file down
load by typing:
FILE
<return>
6. Press F3 to
bring up a file selection menu
7. Select file and
press return
8. Examine the
eForth dictionary by
WORDS
Version
2.04, 2/20/95
This
disk contains the beta version of MuP21 eForth v2.02. The files
are:
readme.seq This file
meta.seq
Metacompiler. It also loads
all other files
ok21c.seq Chuck
Moore's MuP21 assembler
okchar21.seq Character generator and
RS232 driver
kernel.seq 30 eForth
primitives for MuP21
inner.seq Inner
interpreters for MuP21 eForth
eforth.seq High level
eForth source code
p21ef.rom 32K byte
eForth ROM image
Hardware
Requirements
This
eForth is to be used in the MuP21 Development Board (Offete 4012)
or
in the MuP21 Evaluation Kit (Offete 4011).
To run eForth, the
board
needs the following modifications:
1. Replace 74HC138
by a 74ACT138
2. Replace 74HC245
by a 74ACT245
3. Add 0.1 uF
bypass capacitors to 74ACT138 and 74HC574
4. Burn a M27C1001
(200ns or lower) EPROM with p21ef.rom
located between 0-7FFF.
Place it in the ROM socket.
5. Connect pin-9 of
'245 to TX of host RS232 port
6. Connect pin-19
of '574 to RX of host RS232 port
eForth
uses fast I/O mode to communicate with the host. HC parts
are
too slow for the input. Running in
fast mode, there is a
significant
amonut of noise which tends to disrupt the serial
output
line. The bypass capacitors are
needed to quite down
the
system.
Boot
the RS232 Interface
Upon
power up, the big blue OK sign will be shown on the TV screen.
Pressing
the middle switch of the 7 switches will activate the serial
interface
and sends the message "MuP21 eForth V2.02" to the host.
Now
you can talk to MuP21 via the host keyboard/screen.
Try
the following eForth commands:
WORDS
HEX
0 2000 DUMP
SEE
WORDS
.FREE
.BASE
:
LOOPTEST -1 FOR NEXT ;
LOOPTEST
If
the message "MuP21eForth V2.02" is garbled up, the host is not
talking
in 9600 baud, 1 start, 1 stop format.
Change the host
baud
rate to 9600 and reboot MuP21 system.
Then press middle
switch.
If
the message is still not correct, do the following to change
the
baud rate from MuP21. The 7
switches are number 1 to 7, with
switch
1 being the software RESET switch.
1. Press hardware
reset switch. OK must be shown on
TV screen.
Make
sure MuP21 and the host RS232 port are properly connected.
2. Press Switch
3. The TV screen will be darkened.
3. Press Switch
2. Character B will be sent to
host.
Hold
down Switch 2 and use a scope to observed the
waveform. It should be close
to 9600 baud.
4. Press Switch 7
once. This puts MuP21 in a waiting
loop,
waiting for a characte 'B' or 'b' to be transmitted from
the
host.
5. Press 'B' on the
host keyboard.
6. Hold down Switch
2 again, to verify that B's are properly
received by the host.
7. Press Switch 1
once to return to the OK screen. Do
not
hold
it too long to trigger a software reset.
Software
reset will erase the new baud rate you just acquired.
8. Press Switch 4
again to initialize the serial port.
You
should see the eForth sign-on message on the host screen.
Failing that, repeat from Step 1.
MuP21
Hardware Debugger
To
bring up this eForth system, I implemented a simple hardware
debugger
under the OK system. It consists of
4 menus, and the functions
assigned
to switches in the following fashion:
Menu
Switches
7
6
5
4
3
2
1
OK
Debug Dump+ Dump- eForth Test Select Reset
Test
(green) SetBaud
Dump+ Dump- KeyTest CLS EmitTst OK
Select
(blue) Debug Digit3 Digit2 Digit1 Digit0 Stacks Test
Debug
(red) Stacks Go3FF Continu Rpt3FF -- Select Test
Functions
are:
Dump+
Dump next 80 words
Dump-
Dump previous 80 words
eForth
Start eForth, locked to serial line
Reset
Software reset
SetBaud
Wait a 'B' from host and set baud rate
KeyTest
Enter an infinite loop to receive characters from
host and display characters on TV screen
CLS
Darken the TV screen
EmitTest Send 'B' to the host
Digit3
Decrement digit 3 in memory location 3FF
Digit2
Decrement digit 2 in memory location 3FF
Digit1
Decrement digit 1 in memory location 3FF
Digit0
Decrement digit 0 in memory location 3FF
Stack
Dump the stack area from 3B0 to 3FF
User area:
3B0-3BF
Data Stack:
3C0-3DF
Return Stack: 3E0-3FF
IP:
3FC
SP:
3FD
RP:
3FE
Go Address:
3FF
Go3FF
Jump to address in 3FF, init SP to 3C0 and RP to 3E0
Break at the next EXIT
Continue
Continue execution till the next break at EXIT
Rpt3FF
Jump to address in 3FF, do not init SP and RP
To
break at EXIT, eForth needs to be recompiled with the phrase
'
WAIT alias ;;
enabled
and the phrase
'
EXIT alias ;;
commented
out.
With
WAIT installed in places of EXIT at the end of all the colon
definitions,
you can choose a colon definition by put its address
(plus
1, to the address list) in 3FF and press 'Go3FF' switch.
MuP21
will execute the list and stop at the next WAIT (EXIT). The
stacks,
pointers and the user area are refreshed for inspection.
Press
'Continue' will continue the execution and stop at the next
WAIT
(EXIT).
To
select a word to trace, go the the Select Menu and use the
Digit3,
Digit2, Digit1, and Digit0 switches to change the address
in
3FF. When you have the desired
address in 3FF, press 'Debug'
to
go the the Debug Menu. Use Go3FF to
start execution, and
Continue
to trace the code. If you like to
look at other memory
locations,
press 'Test' to get to the Test Menu and then the
Dump
switches to scan the memory. Press
'Debug' to continue
tracing.
This
debugger is very crude and not very convenient. It served
my
purpose of bringing up the interpreter of eForth. Once the
interpreter
is up and working, debugging the rest of the system
is
but a breeze. However, it can be
very useful when you have
to
enhance eForth. So, I present this
debugger as a challenge
to
you. Try to make it more versatile
and easier to use. Extend
it
so you can use it to debug native MuP21 machine code programs.
The
Metacompiler
The
purpose of this metacompiler is to build the eForth system
on
the top of the OK system originated from Chuck Moore. I took a
short
cut. Instead of insisting on
building in in MASM, I tried
to
use the eForth source code provided by Bill Muench. The OK
system
is extended to the point that it can read Bill's Forth
source
code and generates the desired ROM image executable by
MuP21. I am not trying to write a good
metacompiler like Bill's,
only
one which can metacompile the eForth proper.
OK
is first loaded. It is used to
assembler the 30 some kernel
words,
in the machine code of MuP21. All
code words and colon
words
are defined such that future references will compile their
addresses
in the code dictionary. Numbers are
compiled by the
compiler
word LIT, strings are compiled by the compiler word $LIT.
Control
structures are compiled by the redefined words like
IF,
ELSE, THEN, BEGIN, UNTIL, WHILE, REPEAT, AGAIN, etc.
As
the eForth is being built, more and more Forth words are
redefined
to compile their respective address.
In the end, all
words
are compiler words, and doing nothing else but compiling.
It
become extremely dull, as it will echo 'ok' on any thing you
type
and do nothing interesting.
Hence,
the ordering of eForth words is very inportant. If you have
to
use a function, the corresponding word must be compiled after
all
its functions are served.
Memory
Map
OK
0-196
Kernel
197-300
TIB
300-350
User
Area
3B0-3BF
Data
Stack
3C0-3DF
Return Stack
3E0-3FF
Text
Utility 400-4FF
Serial Port
500-5FF
Character Table 600-7FF
DOLIST,DOVAR
800-80F
Variables 810-837
User
Variables 838-849
Colon Words
84A-BFF
DOLIST,DOVAR C00-C0F
Colon Words
C10-FFF
DOLIST,DOVAR
1000-100F
Free
Space
1010-19EE
Name
Dictionry 19EF-1FFF
Free
Memory 2000-AAAA9
Video Buffer
AAAAA-B9658
Free
Memory
B9659-FFFFF
Notice
the DOLIST and DOVAR at the beginning of every
1K
word page which contains colon definitions and variables.
They
are the inner interpreters of colon words and variables
and
they allow words to be referenced across page boundaries.
The
file INNER.SEQ is loaded at the beginning of every page
used
for high level eForth code.
Only
32 words are allocated each for the Data Stack and the
Return
Stack. They seem to be quite
shallow compared to other
Forth
systems. However, 32 words are
adequate. While eForth is
running,
the water mark of the Return Stack is at 21 words and that
of
the Data Stack is at 13. You should
feel comfortable with these
stacks. However, don't get carried away and
start doing recursion
without
relocating the stacks.
Characters
and Words
MuP21
is a 20-bit word addressing machine.
We can pack 2.5 bytes
to
a word, if so desired. However, we
take the simpler approach
in
assigning one byte to a word. It
seems to be quite wasteful,
but
we have 1 MB of ROM space and 1M words of DRAM space. So far,
the
eForth system uses 2K words for code dictionary and less than
2K
words for name dictionary. 1K words
are used by OK and the
kernel,
and 1K words are used by the character table and service
routines. It occupies the lowest 8K words in the
1M DRAM space.
Within
this 8K space, there are still more that 2K words for
dictionary
expansion.
C@
and C! are not defined. @ and ! are
used in their places.
CELLS,
ALIGNED are not needed. CELL+ is 1+
and CELL- is 1-.
A
string is a sequence of words preceeded by a 20-bit count. Strings
are
therefore not limited to 255 bytes.
Theoretically, a string
here
can be 1M words long.
B4. Meta28.seq
comment:
meta.seq, meta-compiler for eForth
high level words, 04feb95cht
Compile ok21c, okchar21, eforth, and
bforth, 11feb96cht
Compile headers in name dictionary,
16feb95cht V2.02
beta version
Update baudRate, !IO, add tv words,
11mar95cht, V2.04
compile ok22c,okchar22, kernel,
inner and eforth
Update ok22c, okchar22c, slow down
I/O for eForth communication.
Release as V2.06.
Use original
74HC138/74HC245/74HC574 IO chip set.
Replace 14.318 MHz clock by 1.8432
MHz clock for stability in RS232.
Rename files as meta26, ok26c,
okchar26.
meta27.seq, include hline27,
okchar27, with retchangle, 24nov95cht
meta28.seq, MuP21h with 82C51 serial
chip, 14mar96cht
Add RECTANGLE to ok28c.seq,
19mar96cht
comment;
ONLY FORTH ALSO DEFINITIONS
empty HEX
WARNING OFF
variable printing?
printing? on
variable debugging?
debugging? off
: .head ( addr -- addr )
printing? @
IF >IN @ 20 word count type
space >IN !
dup .
THEN
;
: CR CR
debugging? @
if .s KEY 0D = abort"
done"
then
;
' dup alias forthDUP
' drop alias forthDROP
' over alias forthOVER
' swap alias forthSWAP
' @ alias forth@
' ! alias forth!
' and alias forthAND
' + alias forth+
' - alias forth-
' word alias forthWORD
' CR alias CRR
' .( alias forth.(
: 2-OR ROT XOR >R XOR R> ;
: 2AND ROT AND >R AND R> ;
: -OR XOR ;
: ADDRESS C 302 PC! DUP FLIP 301 PC! 300 PC! ;
: DISABLE 7 305 PC! 7 306 PC! ;
: ENABLE 6 305 PC! ;
: 8255 ( n -- ) ( ports A,C output,
mode 0)
80 303 PC! ( output )
( C0) 307 PC! ( A,C mode 2, B mode 0 output )
DISABLE ;
C0 8255
ENABLE
: READ 6 306 PC! ;
: WRITE 7 306 PC! ;
: READ-PULSE 4 306 PC! 6 306 PC! ;
: WRITE-PULSE 3 306 PC! 7 306 PC! ;
: ROM@ ( a - b) ADDRESS READ-PULSE
304 PC@ ;
: RAM! ( b a) ADDRESS 304 PC! WRITE-PULSE ;
: CLEAN WRITE 3000 0 DO 0 I RAM! LOOP READ ;
: VIEW ( a) DUP . 10 0 DO CR 10 0 DO DUP ROM@ 3 .R
1 + LOOP LOOP ;
CREATE ram 6000 ALLOT
: RESET ram 6000 ERASE ; RESET
: R@ 3 * ram + DUP 1 + @ FLIP SWAP C@ ;
: R! 3 * ram + SWAP OVER C! SWAP FLIP SWAP 1 + ! ;
: FOUR 4 0 DO DUP R@ AAAAA. 2-OR 6 D.R 1 + LOOP ;
: SHOW ( a) 10 0 DO CR
DUP 3 .R SPACE
FOUR SPACE
FOUR LOOP ;
: SEND1 WRITE 2000 3FFF DO I AAA -OR ram + C@ I 4000 + RAM!
-1 +LOOP READ ;
: SEND2 WRITE 4000 5FFF DO I AAA -OR ram + C@ I RAM!
-1 +LOOP READ ;
: CHECK1 4000 2000 DO I AAA -OR ram + C@ I 4000 + ROM@ 2DUP -OR IF
CR I 3 .R 4 .R 3 .R ELSE 2DROP THEN LOOP ;
: CHECK2 6000 4000 DO I AAA -OR ram + C@ I ROM@ 2DUP -OR IF
CR I 3 .R 4 .R 3 .R ELSE 2DROP THEN LOOP ;
: SEND WRITE 0 1FFF DO I AAA -OR ram + C@ I RAM!
-1 +LOOP READ send1 send2 ;
: CHECK 2000 0 DO I AAA -OR ram + C@ I ROM@ 2DUP -OR IF
CR I 3 .R 4 .R 3 .R ELSE 2DROP THEN LOOP check1 check2 ;
\ comment:
handle outhcb
: writeROMfile ( writeROMfile <outputfile>
<return> )
outhcb !hcb
\ ouput file spec
write-only outhcb hopen
IF
outhcb hcreate abort" Create file error"
cr ." Create "
ELSE cr ."
Update "
THEN
outhcb count type
0.0
outhcb movepointer
\ reset file pointer
2000
0 do
I AAA -OR ram +
1 outhcb hwrite
1- abort" write file error"
loop
4000. outhcb movepointer
\ skip 8K bytes
6000
4000 do
\ this segment in place
I AAA -OR ram +
1 outhcb hwrite
1- abort" write file error"
loop
4000
2000 do
\ relocate to 6000-7FFF
I AAA -OR ram +
1 outhcb hwrite
1- abort" write file error"
loop
outhcb hclose abort" Close file error"
;
\ comment;
CR .( include ok28c )
include ok28c
CR .( include hline27 )
include hline27
CR .( include okchar28 )
include okchar28
CR .( include eforth kernel )
include kernel27
comment:
CR
': CLS
:KEY CLSkey BLANK KEY -;'
': redScreen red SCREEN KEY -;'
': blueScreen blue SCREEN KEY -;'
': greenScreen green SCREEN KEY -;'
CR
:KEY TEST MENU greenScreen
ioTest 50dump+ 50dump- emitTest
CLSkey keyTest IS !main --
:KEY SELECTION MENU blueScreen
IS !debug -- nibble3 nibble2
nibble1 nibble0 showStacks TEST
!debug fix
:KEY DEBUG MENU redScreen
showStacks goAddress continue
repeatAddress -- SELECTION TEST
comment;
\ comment:
SWITCH
\ comment out these lines to activate debugger
40001. p PAGE
BLANK
\ comment;
IS !cold
:KEY coldStart
F3E. # 3FF. # nop a!
!
ljump goAddress
comment:
3FC ORG
F3E. #, 3C0. #, 3E0. #, F3E. #,
SWITCH
\ un-comment these two lines to activate debugger
40001. p PAGE
BLANK
comment;
CODE BYE
\ !main FIX
\ ': MAIN MENU 'OK' DEBUG 50dump+ 50dump- coldStart TEST
SELECTION RESET
': main menu 'ok' 50dump+ 50dump- \ test1 test2 test3
test4 test5
-- coldStart -- -- reset
SWITCH .
begin .
CR 800 ORG
include inner
CR C00 ORG
include inner
CR 1000 ORG
include inner
CR
: again ( a -- )
BRANCH 0 #, ;
: until ( a -- )
QBRANCH 0 #, ;
: if ( -- a )
QBRANCH begin 0. #, ;
: then ( a -- )
begin 0 AAAAA. 2-or rot R! ;
: else ( a -- a )
BRANCH begin forthSWAP 0. #,
then ;
: while ( a -- a' a )
if forthSWAP ;
: repeat ( a' a -- )
again then ;
: for ( -- a )
>R begin ;
: next ( a -- )
doNEXT 0 #, ;
: aft ( a -- a' a" )
forthDROP BRANCH begin 0. #, begin
SWAP ;
: LIT ( d -- )
DOLIT #, ;
: $LIT ( -- )
22 forthWORD count
forthDUP 0 #, ( compile count )
0 DO
count 0 #, (
compile characters )
LOOP
forthDROP ;
' STORE alias !
' AT alias @
' STORE alias C!
' AT alias C@
' (DUP) alias dup
' (SWAP) alias swap
' (DROP) alias drop
' (OVER) alias over
' (AND) alias and
' (XOR) alias xor
' (OR) alias or
' EXIT alias ;;
\ ' WAIT alias ;;
\ debugger
: :: makeHead begin .head CONSTANT
doLIST DOES> forth@ 0 #, ;
: USER makeHead begin .head CONSTANT
doUSER #, DOES> forth@ 0 #, ;
: CREATE makeHead begin .head
CONSTANT doVAR DOES> forth@ 0 #, ;
: VARIABLE CREATE ( 0. #,) ; \
let eForth init its variables
.( include eforth28 )
include eforth28
CRR forth.( done compiling ) CRR
B5. ok28c.seq
( EPROM Programmer, Chuck Moore,
1993 Aug 16)
( modified, C. H. Ting, 1993 Nov 23
for mode 2 operations )
( test text display, 3-4-94 cht )
( allot 3000 bytes for ram, include
OKCHAR, 3-5-94 cht )
( OKCHAR6.SEQ has text demos, called
from TEST. 3-11-94 cht )
( OKCHAR7.SEQ has MuP21.TXT manual
demo. 7-16-94 cht )
( OKCHAR8.SEQ has menu captions,
7-17-94 cht )
( OKCHAR10.SEQ blocks of text and
demo2, 8-8-94 cht )
( OKCHAR11.SEQ parallel output
tests, 8-11-94 cht )
( OK12.seq Bit map display, 9-9-94
cht )
( include OKPICT and compressed
pictures, 10-2094 cht )
( OK13.SEQ, 16 pictures, 10-7-94
cht, with OKPICT13.SEQ )
( include OKPICT14 for plastic
chips, 01nov94cht )
( OK16.SEQ, add nop before a!,
05nov94cht )
( OK16a.SEQ, sram+text, OK16b.SEQ,
sram+picture, OK16c.SEQ, rom+text )
( OK16x.SEQ, experiments with
OKCHAR14, rom+text, 06nov94cht )
( Update OK16c.SEQ from OK16x.SEQ,
09nov94cht )
( OK19c.seq, output tests, RS232
interface, 20jan95cht )
(
Scrollup in okchar16.seq, 24jan95cht )
( ok20c.seq, with meta.seq,
eforth.seq, and bforth, 10feb95cht )
( ok21c.seq, compiled from meta.seq,
11feb95cht )
( ok22c.seq, add rectangle eforth
words, 10mar95cht )
( ok26c.seq, slow down I/O,
11nov95cht )
( ok27c.seq, merge rectangle,
24nov95cht )
( ok28c.seq, add RECTANGLE, 19mar96cht
)
VARIABLE H
: LOC CONSTANT DOES> @ H ! ;
VOCABULARY 8-B 8-B DEFINITIONS ( 8-bit instructions)
: , ( b) H @ ram + C! 1 H +! ;
: INST CONSTANT DOES> @ , ;
: p 44 , , ;
: # AA -OR p ;
41 INST @+ 45 INST @ 51 INST !+ 55 INST !
80 INST com 81 INST 2* 84 INST 2/ 85 INST +*
90 INST -or 91 INST and 95 INST +
C4 INST dup C5 INST over D4 INST nop D5 INST drop
C0 INST pop C1 INST a D0 INST push D1 INST a!
01 INST ;'
18 INST byte A4D LOC :byte
30 INST word A65 LOC :word
AAA LOC ;reset
3A INST 0a! A6F LOC :0a!
24 INST =0
20 INST jump
22 INST start
:0a! a start ( =0) ;' nop nop nop
( jump) @+ a ( start) =0
jump
:byte 2* 2* 2* 2* 2* 2* 2* 2*
push 00 # -or pop -or ;'
:word byte byte !+ ;'
;reset pop pop dup ( clear stack
pointers)
-or a! 0a!
83 p 0E p 0C p word 46 p 0E p 0C p word
55 p AA p 0A p word 21 p 4E p 06 p word
F9 p 4B p 0F p word FC p 0F p 06 p word
55 p 81 p 00 p word 55 p 49 p 08 p word
F9 p 0B p 0F p word 01 p C7 p 0B p word a push
DC p 21 p 06 p word 65 p F5 p 0F p word \
start from AA030
AA p A2 p 0A p word 51 p C1 p 0A p word \
copy 2000 words
FC p 13 p 0B p word 2A p AA p 0A p word ;' \ 11feb95cht
\ header compiler
\ header: | code field | link field | name field
|
\ headers are linked backwords and
fill name dictionary from hi to low
\ memory, towards the code
dictionary.
FORTH DEFINITIONS ( 20-bit instructions)
variable nameH 1FFF nameH !
\ point to next available location
variable lastH 0 lastH !
\ init linkfield address lfa
: nameR! ( n -- )
0 AAAAA. 2-OR nameH @ R!
\ store double to code buffer
1 nameH +!
\ bump nameH
;
: (makeHead)
20 word
\ get name of new definition
dup c@ 2+ negate nameH +!
\ compute cfa
H @ nameR!
\ fill code pointer field
lastH @ nameR!
\ fill link field of last word
nameH @ lastH !
\ save nfa in lastH
dup c@ nameR!
\ store count
count 0 do
count
nameR!
\ fill name field
loop drop
lastH @ 3 - nameH !
\ nameH point to free space
;
: makeHead
>IN @ >R
\ save interpreter pointer
(makeHead)
R> >IN !
\ restore word pointer
;
: compile-only 40. lastH @ R@ 2-OR
lastH @ R! ;
: immediate 80. lastH @ R@ 2-OR lastH @
R! ;
\ Chuck Moore's P21 20 bit assembler
: 2, , , ;
VARIABLE Hi VARIABLE Hw
: ALIGN 10 Hi ! ;
: ORG DUP . CR H ! ALIGN ;
: SWITCH H @ SWAP ORG ;
: IS H @ Hi @ 10 / + 0 2CONSTANT ;
: ALLOT ( n -- ) H +! ;
CREATE mask AA800. 2, 55400. 2, 32A. 2, D5. 2,
: p, H @ R! 1 H +! ;
: #, AAAAA. 2-OR p, ;
: ,w Hw @ R@ 2-OR Hw @ R! ;
: ,I Hi @ 10 AND IF 0 Hi ! H @ Hw ! 0. p, THEN
Hi @ mask + 2@ 2AND ,w
4 Hi +! ;
: INST 2CONSTANT DOES> 2@ ,I ;
C0280. INST com FF3FC. INST nop
: JMP 2CONSTANT DOES> 2@ BEGIN Hi @ 8 AND WHILE nop
REPEAT
,I 3FF AND 155 -OR 0 ,w ALIGN ;
: begin BEGIN Hi @ 10 AND 0= WHILE nop
REPEAT H @ ;
: -;' Hw @ R@ OVER 4000 AND IF 4000 ELSE 8000 THEN 0 2-OR Hw @ R! ;
: p 3314C. ,I p, ;
: -p FFFFF. 2-OR p com ;
: # AAAAA. 2-OR p ;
: -# 55555. 2-OR p ;
: FIX DROP 1 - >R begin 0 AAAAA. 2-OR R> R! ;
( bits 10 8 4 2 1: C0280 30140 0C030
0300C 00C03)
00000. JMP jump 0300C. JMP T=0 03C0F. JMP C=0 0C030. JMP call
0300C. JMP until 03C0F. JMP
-until
: ': begin .head CONSTANT DOES> @ call ;
: :KEY begin .head CONSTANT DOES> @ 0 #, ;
: CODE makeHead :KEY ;
\ for eForth kernel words
: if 155 T=0 Hw @ ;
: -if 155 C=0 Hw @ ;
: skip 155 jump Hw @ ;
: then DUP >R >R begin 3FF AND 155 -OR 0 R> R@ 2-OR R> R! ;
: else skip SWAP then ;
: while if SWAP ;
: -while -if SWAP ;
: repeat jump then ;
30D43. INST @+ ( 33D4F. INST @ ) 3CD73. INST !+ 3FD7F. INST !
C0E83. INST 2*
C328C. INST 2/
C3E8F. INST +*
CC2B0. INST -or CCEB3. INST and CFEBF. INST +
F03C0. INST pop F0FC3. INST a F33CC. INST dup F3FCF. INST over
FC3F0. INST push FCFF3. INST a!
00C03. INST ;'
: !!+ dup ! !+ ;
: dup!!+ dup ! dup !+ ;
: , p !!+ ;
: J FFFFF. 2-OR # !!+ ;
: ljump ' >body @ 0 #
\ get address of target word
push ;' ;
\ long jump
FFFFF. INST drop
33D4F. INST @
( black blue red magenta green cyan yellow white )
( 42108. , 08421. , 10842. , 18C63.
, 21084. , 294A5. , 318C6. , 39CE7. , )
: brown 318C6. p ;
: blue 4A529. p ; : red 5294A. p ; : magenta 5AD6B. p ;
: green 6318C. p ; : cyan 6B5AD. p ; : yellow 739CE. p ;
: black 0. p ; :
white 7BDEF. p ; : silver 39CE7. p ;
( Boot) 0 ORG
': byte 2* 2* 2* 2*
2* 2* 2* FF. #
@+ and -or ;'
': word' a push nop a! @+
2* byte
2* byte
a pop nop a! push
!+ pop ;'
( A) ': BOOT A8030. -# com 800. # ( allow 8K addressing space )
begin push word'
pop 80. # nop
nop \
copy 8K words
( 10) + -until
( Memory Map)
( Host SRAM
DRAM
)
( number number pattern number
pattern
)
( 003 1AA003 C.00AA9 000001
AAAAB DRAM boot )
( 033 1AA033
11
OK code )
(
304
end )
(
330
cos
)
(
340
shapes )
(
350
dot masks )
(
36C
)
( A45 1AAA45
SRAM boot )
( AAA 1AAAAA C.00000
Reset
)
( B98 1AAB98
)
(
100000 8.2AAAA 1000
ABAAA Layout )
(
1B0420
59210
)
(
AAAAA 00000
Video image)
(
ABDE4
UL corner )
(
B9658
)
( IO addresses for development
board)
(
pattern com
)
(
100000 FFFFF slow SRAM
)
(
140000 BFFFF fast SRAM
)
(
180026 7FFD9 write 8255 control
)
(
18000C 7FFF3 read port C
)
(
180024 7FFDB write port C
)
(
1C0000 3FFFF read fast input port )
(
1C0004 3FFF7 write fast output port )
(
1E0028 1FFD7 write configuration )
( Observations )
( over doesn't work )
( 1 -1 + ripples 3 )
( -1 1 + ripples 9 )
( nop + ripples 19+)
( slot0 + ripples 19+)
80 SWITCH
': BSR 0. p dup !+ !+ ( BBBB)
05FF7. , BDEF7. , ;' ( BSRS SSSS)
': HR ( 18) BSR BDFF7. p BDEF7. p ( SSRS SSSS)
over over !+ !+ over over !+ !+ !+ !+
9DEF7. , 00015. , ( KSSS BBBC)
AD6B5. p ( CCCC)
dup !+ dup !+ !+
AD6A0. , ( CCCB)
0. p ( BBBB)
dup !+ !+ ;'
': H HR A0000. # ( 96)
': Bs begin 0. ,
1000. # nop +
-until drop ;'
': Q BSR BDEF7. p dup !+ !+ ( SSSS)
BDC00. , CE000. # Bs ( SSBB)
BSR 9DEF7. , BDEF7. , ( KSSS SSSS)
BDC00. , CE000. # Bs -;' ( SSBB)
': Ss D2000. #
begin BDEF7. , ( SSSS)
1000. # nop +
-until
FA000. # Bs -;'
': V BSR BDEF7. , Ss ( SSSS)
BSR 9DEF7. , Ss -;' ( KSSS)
': a+ a nop nop + a! ;'
cr
SWITCH
AAAAA. # nop a!
( AAAAA VR1 21 114* 1+)
Q Q Q V V V Q Q Q
H H H H H H H H H H H H
ABDD2. J
( AB405 VR2 22 114 1+)
HR D9000. # Bs Q Q Q V V V Q Q Q
C7000. # Bs H H H H H H H H H H H H
ABDE6. J
( ABDD2 482 20*) AE37F. # E1E00. # begin HR
push dup com !+ dup !+ 66. # nop +
pop 100. # nop +
-until
( AE37A 482 66*) ABDFA. # E2000. # begin 65. # a+
push dup com !+ 14. # nop nop +
pop 100. # nop +
-until
65. # a+ AB405. J
65. # a+ AAAAA. J
( BA386)
cr
SWITCH
( 66 1A * = A5C, 14 1A * = 208)
': UL ABFEC. # skip (
1)
': L2 AC1F4. # skip (
2)
': LL ADE64. # ( 16)
then then a! @ FFFFF. # -or 8. # nop nop + a! ;'
': 100ms 2. #
': -s
1. #
begin +* -until
drop drop ;'
': KEY? ( n - n) 100ms
\ 70020.
( '245 input )
\ 7FFF3. p com nop a! @
( port 6 )
7FFFF. p com nop a! @ (
port 0 for new pcb, slow i/o )
\ 3FFFF. p com nop a! @
( port 0 fast i/o )
55. # -or 7F. # and ;'
:KEY --
': KEY begin KEY? until
IS 'menu 0. # nop a!
begin @+ drop 2/ while repeat
@ push ;'
': MENU 'menu # nop a! pop
dup push ! ;'
': PAGE 1FFD7. p com nop a! ! ;'
': -a com a nop nop + nop a! ;'
begin .
cr
100 ORG
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
dup !+ dup !+ dup !+ dup !+ dup !+ dup !+
IS 'one dup !+ dup !+
': TWOS !+ skip
begin a push
IS 'twos nop nop IS 'color
0. # TWOS -;'
SWAP then 66. # pop nop nop + nop a!
': HIGH ( 22) 1. # nop nop +
-until drop ;'
': COLOR ( 12) a push 'color # nop a! !
pop nop a! ;'
': WIDE ( 22) a push 'twos # nop a! 2/ 2/ dup 2/ 22065. p nop + !
1. # and if 28860. p
else AA861. p then -or 'one # nop a! !
pop nop a! ;'
': SCREEN
IS 'XY
AE37F. # nop a!
IS 'width
180. # WIDE
IS 'height
1E2. -# HIGH -;'
': BLANK black COLOR SCREEN ;'
CODE RECTANGLE ( x y width height --
)
a push 3. # com
+ dup 3FC. # nop
\ SP-4
a! !+ pop !+
\ save new SP, IP and RP
pop ! nop a!
\ put SP-3 in A
@+ drop @+ 2/
\ get x and divide it by 4 for an address
2/ @+ dup 2*
\ get y and multiply it by 66H
+ 2* dup 2*
2* 2* 2* nop
+ nop nop +
\ y*66+x/4
AE37F. # nop nop +
\ real screen address
@+ @+ com 'height # \
store negated height
a! ! 'width # nop
\ store width
a! ! 'XY # nop
\ store screen address
a! !
SCREEN
\ draw the rectangle
3FC. # nop a! @+
\ restore new SP, IP, and RP
@+ @ push nop
a! @+ push ;'
\ next
cr
': 'OK 80. # WIDE 34. -# HIGH
20. # WIDE 68. -# HIGH
80. # WIDE 34. -# HIGH
3E0F. # -a 20. # WIDE 68. -# HIGH
3E17. # -a 20. # WIDE 4E. -# HIGH
80. # WIDE 34. -# HIGH
20. # WIDE 4E. -# HIGH
52C7. # -a 4E. -# HIGH
14B0. # a+ 4E. -# HIGH -;'
': 'OK' BLANK
08421. p COLOR L2
530. # a+ 'OK
blue COLOR L2
'OK
KEY
:KEY RESET 00000. p PAGE
10. # nop a! BOOT
cr
begin .
B6. hline27.seq
\ hline.seq, draw a horizontal line,
09sep96cht
\ hline26.seq, polishing up,
16sep95cht
\ hline27.seq, merge into
eForth2.07, 24nov95cht
\ Use 0F0-0F7 for end masks, 0FC-0FF
for parameters, 24nov95cht
cr
comment:
': vline ( height mask color -- ,
starting addr in A )
over com and push push
\ clear unwanted color bits
begin pop pop over @
\ clear color bits in memory
and over -or
!
\ add needed pattern bits and store
push push a 66.
#
+ nop a! 1.
#
\ ready A for next line
+ -until
\ decrement height until zero
pop pop drop drop drop ;'
comment;
': initHline
\ ': corners ( x1 x2 y1 y2 --,
stored in 0FB-0FF, x1,x2,count,ul,colorPtr )
\ reorder x1,x2 and y1,y2 so that
x1<x2 and y1<y2
\ if x1>384 quit, clip x2 to 384
\ if y>482 quit
\ store x1 x2 -count ul colorPtr in
0FB-0FF
\ colorPtr points to a 16 word color
array, normally at 300
push push over over
\ x1 x2 x1 -x2 --
com nop nop +
-if drop push nop a!
\ x2>x1, push x2, save x1
else drop nop a! push
\ x1>x2, save x2, push x1
then
a dup -180. # nop
+ -if drop drop pop drop
\ if x1>384, quit!
pop drop pop ;'
then
drop 0FB. # nop a!
!+ pop dup -180. #
\ save x1 in 0FC
+ -if
drop drop 180. #
!+
\ if x2>384, replace it by 384
else drop !+
\ save x2 in 0FD
then
pop pop over over
\ y1 y2 y1 y2 --
com nop nop +
-if !+ drop
\ y1<y2, save y1-y2 as count
else com !+ push drop
\ y1>y2, save y2-y1 as count
pop
then
\ (lesser of y1 and y2) --
dup -1E2. # nop nop
\ test y
+ -if drop drop pop ;'
\ y>482, quit!
else drop
then
IS colorPtr
300. # over 7. # and
\ pick two color patterns from array
2* -or push dup
2* nop nop +
\ 66*y1
2* dup 2* 2*
2* 2* nop nop
+ ( 800.) AE37A. # nop nop \ 66*y+UL
+ !+ pop !
\ save ul and color ptr in 0FE-0FF
;'
': hLine
\ draw one horizontal line
\ ': singleCell
0FB. # nop a! @+
@+ over over -or
\ get x1 and x2 from 0FC
FFFFC. # and
if
\ x1=x2 except 2 lsb's
drop drop
\ keep only x1 for leftEnd
else
\ no middle section to show
drop dup 2/
2/
\ x1 x2 x2/4 --
@+ over nop
nop
\ x1 x2 x2/4 ul x2/4 --
+ push 1. #
and
\ x1 x2 LSB(x2/4) --
@ nop nop +
\ x1 x2 colorPtr --; R: addr --
a! @ push
push
\ x1 x2 --; R: addr color x2 --
3. # and 0F0. #
-or
\ addr(x1mask) --
a! @ pop 3.
#
\ x1mask x2 3 --
and 0F4. # -or
nop
\ x1mask addr(x2mask) --
a! @ and
pop
\ mask color --
pop nop a!
over
\ mask color mask --; addr in A
and push com
@
\ /mask mem --
and pop -or
!
\ --
pop ;'
then
\ ': leftEnd ( x1 -- )
dup 3. # and 0F0. #
+ nop a! @
\ x1 mask --
push 2/ 2/ 0FE. #
\ x1/4 0FE --
a! @+ over nop
\ x1/4 ul x1/4 --
+ push 1. # and
\ (x1/4)and1 --; R: mask addr --
@ nop + nop
\ colorPtr --
a! @ pop nop
\ color addr -- ; R: mask --
a! pop dup push
\ mask color bits
and @ pop com
\ mask mem bits
and -or !+
\ write new mem bits to memory
\ ': middle ( -- )
a push 0FB. # nop
\ R: x1addr --
a! @+ FFFFC. # and
\ strip off ls 2 bits from x1
@+ com nop nop
\ x1 -x2 --
+ 4. # nop nop
\ discard count
+ @+ drop @+
\ discard ul
drop @ nop a!
\ x1-x2+1 --; colorPtr in A
pop dup push 1. #
\ x1-x2 x1addr -- ; R: x1addr --
and if
\ from x1addr determine color order
@+ push @
pop
\ x1-x2 color2 color1 --
else @+ @
\ x1-x2 color1 coler2 --
then
\ push push drop 0F0. #
\ x1-x2+1 0F0. --; R: x1addr col col --
\ a! dup !+ pop
\ dump stack for debugging
\ dup !+ pop dup
\ !+ pop dup !
\ push push push nop
push push drop nop
a! pop pop a
pop nop a!
\ color1 color2 x1-x2+1 x1addr --
\ x1addr is now in A
begin
\ color1 color2 count --, x1addr in A
8. # nop nop +
-while
push over !+ dup
\
write 2 words at a time
!+ pop
repeat
4. # and
if drop drop drop
\ write odd word
else drop drop !+
then
\ ': rightEnd ( --, A has memory
address )
a push 0FC. # nop
\ 0FD. --; R: x2addr --
a! @+ @+ drop
\ x2 --
@+ drop nop nop
\ discard counts and ul
@ pop dup push
\ x2 colorPtr x2/4 --
1. # and nop +
\ x2 colorPtr' --
a! @ over 3. #
\ x2 color x2 3
and 0F4. # nop +
\ x2 color maskAddr --
a! @ dup push
\ x2 color mask --
and pop pop nop
\ x2 color.mask mask x2addr --
a! com @ and
\ x2 color.mask mem/mask --
-or ! drop ;'
CODE RECT ( x1 x2 y1 y2 -- )
a push 3. # com
+ 3FC. # nop a!
dup !+ pop !+
\ save SP, IP, and RP in this order
pop ! nop a!
@+ drop @+ @+
\ fetch x1, x2, y1, and y2 from DS
@+ @
initHline
\ prepare data in 0FB-0FF
begin
hLine
\ write one line
0FD. # nop a!
@
\ increment count
1. # nop nop +
-if drop 3FC. #
nop a!
\ overflow, restore SP, IP and RP
@+ @+ @ push
a! @ push ;'
\ rectangle completed. exit
else !+ @ 66. #
nop
\ store bumped count
+ !+ @ 2. #
\ add 66 to ul
+ 30F. # and !
\ add 2 to colorPtr
then
jump
\ repeat
CODE SetColor ( color -- )
\ set color in 8x8 pattern array
a push dup a!
\ save IP
@ 7BDEF. # and
\ get color from DS
300. # nop a! 10. #
\ init shift-counter to do 16 loops
begin over !+ 2*
\ write pattern, bump counter
-until
drop dup -or com
\ decrement SP
+ pop nop a!
\ restore IP and do next
@+ push ;'
comment:
:KEY newColor ( -- )
IS 'newColor
\ where new pattern comes from
0. # nop a! 300. #
\ source in A, ( dest 10 -- )
10. #
begin
push push @+
7BDEF. #
\ dest pattern --
and AAAAA. # -or
a
\ dest --, R: count pattern source --
pop nop a!
push
\ dest in A, store pattern, source --
!+ a pop
nop
\ source in A
a! pop 2*
\ dest count*2 --
-until
drop drop a 'newColor #
\ preserve newColor for next time
a! !
0. # 17F. # over 1E0. #
\ plot screen with new pattern
rectangle
KEY
comment;
cr
begin 300 org
\ color as patterns
7BDEF. p, 7BDEF. p, 7BDEF. p, 7BDEF.
p,
7BDEF. p, 7BDEF. p, 7BDEF. p, 7BDEF.
p,
7BDEF. p, 7BDEF. p, 7BDEF. p, 7BDEF.
p,
7BDEF. p, 7BDEF. p, 7BDEF. p, 7BDEF.
p,
0F0 org
7BDEF. #, 03DEF. #, 001EF. #, 0000F.
#,
78000. #, 7BC00. #, 7BDE0. #, 7BDEF.
#,
ORG
begin .
cr
B7. okchar28.seq
\ Text utility for MuP21, 05mar94cht
\ Save return stack in character.
06mar94cht
\ TextLine ok. 07marcht okchar3.seq
\ Foreground background colors,
07mar94cht okchar4.seq
\ Use 'screen to store screen
address, 09mar94cht
\ Use 'pattern to store pattern
address, 09mar94cht
\ Preliminary ASCII dump using
number, 09mar94cht okchar5.seq
\ ASCII dumps and character set
demos. 11mar94cht okchar6.seq
\ Integrated to ok4.seq
\ Interface to an Apple II keyboard.
20apr94cht
\ Display text blocks,
13jul94cht okchar7.seq
\ Display captions, 17jul94cht
okchar10.seq
\ Display pictures, 10sep94cht
okchar12.seq
\ Display compressed picture,
25sep94cht
\
okpict.seq, decompression in P21
\
okcomprs.seq, compress .bmp to .p21
\
picture.seq, write .p21 file to sram
\ Replace inline code with count
loops, 25oct94cht
\ Optimize nibble routines, reduce
stack depth, 29oct94cht, okchar14.seq
\ prevent
hickup in nibble, 30oct94cht
\ okchar19, add scrollUp, 24jan95cht
\ okchar20, inproved baudRate,
100us, and 50us, 10feb95cht
\ okchar21, ?RX, TX!, and !IO,
17feb95cht
\ okchar22, add text word set,
rewrite 100us and baudRate, 08mar95cht
\ okchar26, use slow I/O ports for
RS232 stability, 11nov95cht
\ okchar28, MuP21h with 82C51,
14mar96cht
CR
begin
400 ORG
( 16 patterns for 16 nibbles )
00000. #, 0000F. #, 001E0. #,
001EF. #,
03C00. #, 03C0F. #, 03DE0. #,
03DEF. #,
78000. #, 7800F. #, 781E0. #,
781EF. #,
7BC00. #, 7BC0F. #, 7BDE0. #,
7BDEF. #,
00000. #, 00000. #, 00000. #,
00000. #, ( for blank underline )
00000. #, 00000. #, 00000. #,
00000. #, ( save return stack in 414-417 )
00000. #, ( save screen address )
420 ORG
( color table )
00000. #, 08421. #, 10842. #, 18C63.
#,
21084. #, 294A5. #, 318C6. #, 39CE7.
#,
42108. #, 4A529. #, 5294A. #, 5AD6B.
#,
6318C. #, 6B5AD. #, 739CE. #, 7BDEF.
#,
': nibble ( 'nibble has pattern,
will be divided by 16 )
( 'screen has screen address, stack depth=3 )
IS 'nibble
\ avoid pass it on the stack, 10/29/94
0. # 0F. # and 400. # \
get pattern addres
-or nop a! @ dup a!
\ get pattern
IS 'foreground
7BDEF. # and a com
\ get foreground color
IS 'background
0. # and -or
\ add background color
AAAAA. # -or
\ convert to screen pattern
IS 'screen
3F0. # a!
\ get screen address
dup ! a
\ write to screen
66. # nop nop +
\ get next line address
nop a! !+
\ write to next line
a -66. # nop +
'screen # nop a! !
\ save screen address
'nibble # nop a! @
\ update 'nibble
2/ 2/ 2/ 2/
\ shift to next nibble
! ;'
': setForeground ( color# -- )
0F. # and 420. # -or
\ get color from color table
a! @
': foreground ( color -- )
'foreground # nop a! ! ;'
': setBackground ( color# -- )
0F. # and 420. # -or
\ get color from color table
a! @
': background ( color -- )
'background # nop a! ! ;'
CR
': 2nibbles ( -- )
\ write out two nibbles on two lines
nibble nibble
\ write out two nibbles
'screen # nop a! @ CA. #
\ skip one line
nop nop + ! ;'
\ move to next screen line
': 4nibbles ( --, stack depth=3 )
IS 'pattern
600. # nop a! @+
\ get a character pattern word
a 'pattern # nop a! !
\ save pattern address
'nibble # nop a! !
\ store dot pattern
2nibbles
\ write 1st two lines
2nibbles -;'
\ repeat 2nd line
CR
': character ( -- , stack depth=3 )
414. # nop a! pop !+
\ save R
pop !+ pop !+ pop !
\ save R, R1-3
IS 'character
0. # 7F. #
\ get character and use only 7 bits
and 2* 2* 600. #
\ n*4, offset into char table
-or 'pattern # nop a! !
\ add offset to char table
4nibbles
\ output 4 nibbles
4nibbles
\ output one nibble from 2nd pattern
4nibbles
\ output 3rd pattern
4nibbles
\ output 4th pattern
'pattern # nop a! 600. # ! \ null
pattern
4nibbles
\ output underline
'screen # nop a! @ -7F6. # \ move
screen address to next character
nop nop + ! nop nop \ in
the same character line
417. # a! @ push
416. # a! @ push
415. # a! @ push
414. # a! @ push
;'
': showCharacter ( char -- )
'character # nop a! !
character
-;'
': textLine ( n -- )
\ 32 text lines of 40 characters
push FF00. # pop nop \
7F8=20 scan lines
+* 2/ nop nop
\ 7F8*n
+* 2/ nop nop
+* 2/ nop nop
+* 2/ nop nop
+* 2/ AEDE2. # nop
\ UL. AE37A+A5C+C
nop + 'screen # nop a!
! drop ;'
\ save in 'screen
CR
': digit ( -- )
IS 'number
\ where number is to be printed
AC008. # 0F. # and dup \ retain
only the last nibble
9. -# nop nop +
\ is it less then 10?
-if
drop 37. #
\ yes, make it a digit
else
drop 30. #
\ no, make it A-F
then
+ showCharacter
\ print to screen
'screen # nop a! @
\ backup character pointer
3. -# nop nop + !
'number # nop a! @
\ divide number by 16
2/ 2/ 2/ 2/
\ get next nibble in 'number
! ;'
\ store number
': number ( n -- )
'number # nop a! !
\ store number into 'number in digit
digit digit
\ print nibbles from right to left
digit digit digit
'screen # nop a! @ 16. #
\ space to next number field
nop nop + ! ;'
CR
': 4dump
\ dump 4 consecutive locations
IS 'row#
0. # textLine
'screen # nop a! @ 10. #
nop nop + !
IS 'address
0. # number
'address # nop a! @
a! @ number
'address # nop a! @
1. # + nop a!
@ number
'address # nop a! @
2. # + nop a!
@ number
'address # nop a! @
3. # + nop a!
@ number
'address # nop a! @
4. # nop nop + !
'row# # nop a! @
1. # nop nop +
! ;'
:KEY 50dump-
\ dump 80 locations backward
FFF60. # 'address # nop a! @
nop nop + !
:KEY 50dump+
\ dump 80 locations foreward
': 50dump
0. # 'row# # nop a! !
1. #
begin 4dump
2*
-until
drop
ljump KEY
CR
': 25us
( 1/2 bit delay )
8. # skip
': 100us
( 1 bit delay in serial I/O )
2. #
( 100 us is about 1 bit at 9600 baud )
then
IS 'speed
-3FF. #
( 256 cycles for 50us, 512 for 100us )
begin +* nop -until
drop drop ;'
( restore IO port in A )
CODE SLOW ( -- , reduce jitter in
video )
a push 'speed # nop
a! -FFFF. # ! pop
nop a! @+ push
;'
CODE FAST ( -- , for file
downloading )
a push 'speed # nop
a! -3FF. # ! pop
nop a! @+ push
;'
CODE !IO
( initialize 82C51 )
a push
( save IP on S, SP IP -- )
7FFFC. p com nop a! ( slow I/O port, SP IP
addr -- )
0. p ! 25us
( 3 default 0's to init 80C51 )
0. p ! 25us
0. p ! 25us
40. p ! 25us
( reset )
CE. p ! 25us
( 16x, 8 data bits, 2 stop bits, no parity)
27. p ! 25us
( enable Tx, Rx, /DTR, /RTS )
pop nop a!
( restore IP and SP )
@+ push ;'
( next )
comment:
:KEY ioTest
7FFFC. p com nop a! ( slow I/O port, SP IP
addr -- )
0. p ! 25us
( 3 default 0's to init 80C51 )
0. p ! 25us
0. p ! 25us
40. p ! 25us
( reset )
CD. p ! 25us
( 1x, 8 data bits, 2 stop bits, no parity)
27. p ! 25us
( enable Tx, Rx, /DTR, /RTS )
ljump KEY
comment;
CODE ?RX ( -- c true | false, get
character )
25us
a push
( save IP )
7FFFD. p com nop a! ( slow status port in
82C51 )
comment:
@ AA. # -or 38. # and ( any error? )
if drop nop a! @+ ( yes,
push false on data stack )
dup -or ! a
7FFFC. p com nop
a! ( clear error )
37. p !
pop nop a!
@+ push ;'
( return with a false flag )
else drop
( no error, continue )
then
comment;
@ com 2. # and
( RxRDY? )
if 7FFFF. p com nop a! ( read character from 82C51 )
drop @ AA. # -or
FF. # and push
nop ( get SP into A )
a! @+ drop
pop ( bump SP and push character
)
!+ -1. # !
( push -1 flag )
else push nop a! @+ ( else push false flag
on data stack )
drop pop !
then
a pop nop a!
( restore SP and IP )
@+ push ;'
( next )
comment:
:KEY keyTest
10. # textLine
7FFFD. p com dup a! ( slow status port in
82C51 )
begin
drop 25us
@ com 2. #
and (
RxRDY? )
until
7FFFF. p com nop a! ( read character from
82C51 )
drop @ AA. # -or
FF. # and
( get SP into A )
showCharacter
ljump KEY
comment;
CODE TX! ( c -- )
a push
7FFFD. p com dup a! ( status port in 82C51
)
begin
100us
drop @ 4. #
and ( wait
for TxEmpty )
until
drop dup nop a!
( save IP on RS, put SP in A )
@ AA. # -or nop
7FFFE. p com nop a!
! dup dup -or
( data output port in 82C51 )
com nop nop +
( send character out )
pop nop a!
( decrement S, restore I )
@+ push ;' (
next )
comment:
:KEY emitTest
7FFFE. p com nop a! ( status port in 82C51
)
42. p !
ljump KEY
comment;
\ comment:
CR
': move20words ( source in A, dest
on stack, a -- a' )
push 1. #
\ save dest, introduce count
begin
@+ pop a
push
\ get data, exchange source and dest
a! !+ pop a
\ store data, exchange source and dest
push nop a!
2* -until
drop pop ;'
\ restore destination
': scrollUp ( -- )
AEDE2. 7F8. D+ # nop a! \ init
source
AEDE2. #
\ init destination
E8400. #
\ move 19x20 scan lines
begin push
move20words
\ copy 80 words of a line
move20words
move20words
move20words
a 16. # nop
nop
\ move source to next line
+ nop a! 16.
#
\ move dest to next line
+ pop 100. #
nop
\ loop 320 lines
+ -until
drop drop ;'
CR
CODE FG ( color# -- )
a push dup a!
\ get SP
@ 0F. # and 420. #
-or nop a! @
\ get color
dup 'foreground # nop a! \ put in
'foreground for characters
! AAAAA. # -or 'color #
a! ! pop nop
\ also put in 'color for SCREEN
a! dup dup -or
\ restore IP, decrement SP
com nop nop +
@+ push ;'
CODE BG ( color# -- )
a push dup a!
\ get SP
@ 0F. # and 420. #
-or nop a! @
\ get color
dup AAAAA. # -or nop
'background # nop a! ! \
put in 'background for characters
'color # nop a! !
\ also put in 'color for SCREEN
pop nop a! dup
\ restore IP, decrement SP
dup -or com nop
+ @+ push ;'
\ next
CODE tvAT ( x y -- )
\ convert character coordinates to 'screen
a 3FC. # nop a!
!+ pop !+ dup
dup -or com nop
+ dup ! nop
a! @+ @
textLine
2* 'screen # nop a!
\ add 2x to 'screen
@ nop + !
3FC. # nop a! @+
@+ push push @
pop nop a! dup
dup -or com nop
+ @+ push ;'
\ next
CODE tvEMIT ( char -- )
a 3FC. # nop a!
!+ pop !+ dup
! nop a! @
showCharacter
3FC. # nop a! @+
@+ push push @
pop nop a! dup
dup -or com nop
+ @+ push ;'
\ next
CODE tvCR
a 3FC. # nop a!
!+ pop !+ !
\ save IP, RP, SP
scrollUp
12. # textLine
3FC. # nop a! @+
@+ push push @
pop nop a!
@+ push ;'
\ comment;
begin .
CR
600 ORG ( character table )
0000. #, 0000. #, 0000. #, 0000. #,
24C3. #, 185A. #, 24DB. #, 00C3. #,
E7C3. #, FFBD. #, E73C. #, 00C3. #,
EE00. #, EFEF. #, 83C7. #, 0001. #,
8301. #, EFC7. #, 83C7. #, 0001. #,
C300. #, FF81. #, 80FF. #, 0081. #,
8301. #, EFC7. #, 01EF. #, 0083. #,
0000. #, C381. #, 0081. #, 0000. #,
FFFF. #, 3C7E. #, FF7E. #, FFFF. #,
C300. #, 1824. #, 2418. #, 00C3. #,
3CFF. #, E7DB. #, DBE7. #, FF3C. #,
70F1. #, C7D0. #, 6C6C. #, 00C7. #,
E700. #, 3C3C. #, 81E7. #, 81E7. #,
6040. #, 4070. #, CF40. #, 008F. #,
A0C0. #, B0D0. #, 9F9F. #, F1F1. #,
2900. #, 44C7. #, C76C. #, 0029. #,
0000. #, 8706. #, 87E7. #, 0006. #,
0000. #, E160. #, E1E7. #, 0060. #,
E781. #, 8181. #, 8181. #, 81E7. #,
6666. #, 6666. #, 0066. #, 0066. #,
6BFF. #, 6367. #, 6363. #, 0063. #,
1CE7. #, 22CD. #, F122. #, E738. #,
0000. #, E700. #, 00E7. #, 0000. #,
E781. #, 8181. #, 81E7. #, FF00. #,
E781. #, 8181. #, 8181. #, 0081. #,
8181. #, 8181. #, E781. #, 0081. #,
4000. #, FF60. #, 4060. #, 0000. #,
0200. #, FF06. #, 0206. #, 0000. #,
0000. #, 0C00. #, 0C0C. #, 00FF. #,
4200. #, FF66. #, 4266. #, 0000. #,
0000. #, 8301. #, EFC7. #, 0000. #,
0000. #, EF00. #, 83C7. #, 0001. #,
0000. #, 0000. #, 0000. #, 0000. #,
0303. #, 0303. #, 0003. #, 0003. #,
6666. #, 0000. #, 0000. #, 0000. #,
C6C6. #, C6EF. #, C6EF. #, 00C6. #,
C701. #, C72D. #, C768. #, 0001. #,
690F. #, 81CF. #, 27E3. #, 00ED. #,
8403. #, 8703. #, CCEC. #, 0087. #,
C0C0. #, 0081. #, 0000. #, 0000. #,
0601. #, 0C0C. #, 060C. #, 0001. #,
C001. #, 6060. #, C060. #, 0001. #,
4500. #, EF83. #, 4583. #, 0000. #,
8100. #, E781. #, 8181. #, 0000. #,
0000. #, 0000. #, 0000. #, 0781. #,
0000. #, E700. #, 0000. #, 0000. #,
0000. #, 0000. #, 0000. #, 0081. #,
6020. #, 81C0. #, 0603. #, 000C. #,
ECC7. #, 6FED. #, 6E6E. #, 00C7. #,
8381. #, 8187. #, 8181. #, 00C3. #,
6CC7. #, C060. #, 0603. #, 00EF. #,
6CC7. #, C360. #, 6C60. #, 00C7. #,
E1E0. #, 6663. #, 60EF. #, 0060. #,
0CEF. #, CF0C. #, 6060. #, 00CF. #,
6CC7. #, CF0C. #, 6C6C. #, 00C7. #,
60EF. #, 81C0. #, 0603. #, 0006. #,
6CC7. #, C76C. #, 6C6C. #, 00C7. #,
6CC7. #, E76C. #, 6C60. #, 00C7. #,
0300. #, 0000. #, 0300. #, 0000. #,
0300. #, 0000. #, 0300. #, 0002. #,
C100. #, 0603. #, C103. #, 0000. #,
0000. #, 00E7. #, 00E7. #, 0000. #,
0700. #, C081. #, 0781. #, 0000. #,
6CC7. #, 81C0. #, 0003. #, 0003. #,
28C7. #, AAA9. #, E9AA. #, 00C7. #,
6CC7. #, EF6C. #, 6C6C. #, 006C. #,
66CF. #, C766. #, 6666. #, 00CF. #,
6CC7. #, 0C0C. #, 6C0C. #, 00C7. #,
66CF. #, 6666. #, 6666. #, 00CF. #,
26EF. #, 8786. #, 2686. #, 00EF. #,
26EF. #, 8786. #, 0686. #, 000F. #,
6CC7. #, 0C6C. #, 6CED. #, 00C7. #,
6C6C. #, EF6C. #, 6C6C. #, 006C. #,
81C3. #, 8181. #, 8181. #, 00C3. #,
C0E1. #, C0C0. #, CCC0. #, 0087. #,
CC6C. #, 0F8D. #, CC8D. #, 006C. #,
060F. #, 0606. #, 2606. #, 00EF. #,
EE6C. #, 6DEF. #, 6C6C. #, 006C. #,
6E6C. #, ED6F. #, 6CEC. #, 006C. #,
6CC7. #, 6C6C. #, 6C6C. #, 00C7. #,
66CF. #, C766. #, 0606. #, 000F. #,
6CC7. #, 6C6C. #, 6C6C. #, C0C7. #,
66CF. #, C766. #, 6666. #, 006E. #,
6CC7. #, C70C. #, 6C60. #, 00C7. #,
A5E7. #, 8181. #, 8181. #, 00C3. #,
6C6C. #, 6C6C. #, 6C6C. #, 00C7. #,
6C6C. #, 6C6C. #, C66C. #, 0083. #,
6C6C. #, 6C6C. #, EE6D. #, 006C. #,
C66C. #, 8383. #, C683. #, 006C. #,
6666. #, C366. #, 8181. #, 00C3. #,
6CEF. #, 81C0. #, 6603. #, 00EF. #,
81C1. #, 8181. #, 8181. #, 00C1. #,
060C. #, 8103. #, 60C0. #, 0020. #,
0307. #, 0303. #, 0303. #, 0007. #,
0000. #, 8301. #, 6CC6. #, 0000. #,
0000. #, 0000. #, 0000. #, FF00. #,
0303. #, 0081. #, 0000. #, 0000. #,
0000. #, 60C7. #, 6CE7. #, 00E7. #,
0C0C. #, 6CCF. #, 6C6C. #, 00CF. #,
0000. #, 6CC7. #, 6C0C. #, 00C7. #,
6060. #, 6CE7. #, 6C6C. #, 00E7. #,
0000. #, 6CC7. #, 0CEF. #, 00C7. #,
66C3. #, 0F06. #, 0606. #, 0006. #,
0000. #, 6CE7. #, E76C. #, C760. #,
0C0C. #, 6CCF. #, 6C6C. #, 006C. #,
0081. #, 8183. #, 8181. #, 00C3. #,
C000. #, C100. #, C0C0. #, 87CC. #,
0C0C. #, 8D6C. #, 8D0F. #, 006C. #,
8183. #, 8181. #, 8181. #, 00C3. #,
0000. #, EFEE. #, 6C6D. #, 006C. #,
0000. #, 6CCF. #, 6C6C. #, 006C. #,
0000. #, 6CC7. #, 6C6C. #, 00C7. #,
0000. #, 6CCF. #, CF6C. #, 0C0C. #,
0000. #, 6CE7. #, E76C. #, 6060. #,
0000. #, 67ED. #, 0606. #, 0006. #,
0000. #, 0CC7. #, 60C7. #, 00C7. #,
8181. #, 81E7. #, 8181. #, 00E1. #,
0000. #, 6C6C. #, 6C6C. #, 00E7. #,
0000. #, 6C6C. #, C66C. #, 0083. #,
0000. #, 6C6C. #, EF6D. #, 006C. #,
0000. #, C66C. #, C683. #, 006C. #,
0000. #, 6C6C. #, E76C. #, C760. #,
0000. #, C0EF. #, 0681. #, 00EF. #,
81E0. #, 0781. #, 8181. #, 00E0. #,
8181. #, 0081. #, 8181. #, 0081. #,
030E. #, C103. #, 0303. #, 000E. #,
0000. #, A907. #, 00E0. #, 0000. #,
0000. #, C381. #, FF66. #, 0000. #,
ORG
B8. kernel27.seq
\ eForth Kernel for MuP21,
21mar94cht
\ eforth1.seq, update for plastic
chip, 03feb95cht
\ kernel27.seq, comment out
debugging aids, 24nov95cht
\ Keep 0 page usage to
2FF. 300-3FF needed by system.
comment:
The Forth Virtual Engine is:
I IP A
register
Instruction pointer
S SP T
register
Data stack pointer
R RP R
register
Return
stack pointer
Both the data and return stacks are
in external memory. The
registers R1-R3, and S1-S5 are
free. The three registers A, T
and R form a very powerful cluster
to support a Forth Virtual
Engine.
A register is used to host IP
because it leads to the most
efficient $next:
@+ push ;
To address data stack, one can
exchange S and I by
a push a! pop or push a pop a!
To address return stack, one can
exchange R and I by
a pop a! push or pop a push a!
Because A register has the
self-incrementing feature, stacks
can be addressed conveniently
towards the high memory. It is
thus chosen that the stacks grow
towards high memory. To pop
items off the stack, the stack
pointer must be decremented
explicitly.
Names of words are in a separated
head dictionary. Only executable
code are in the code
dictionary. High level words are
also in a
separated segment of memory. Code words, stacks, and user variables
must be in one 1K page for best
performance.
Memory allocation:
0 Boot code
400 Screen
and keyboard drivers
600
Character table
800 Code
words
B00 User
variables
BB0 Return
stack, for dump
BD0 Data
stack
BF0 Test
code
BFC Saved
SP, IP, RP, R1
C00 Colon
words
1000 Headers
2000 Free space
comment;
CR .( kernel words ) CR
hex
comment:
?RX TX! IO! are defined in
okchar20.seq
CODE ?RX
CODE TX!
CODE !IO
comment;
CODE doLIT
@+ a push push
\ get literal, save it and I
a! pop @+ drop
\ increment S for pushing
! a pop nop
\ push literal on stack, restore I
a! @+ push ;'
\ $next
CODE EXIT
\ undo nest
pop nop a! @
\ get new I from return stack
a dup dup -or
\ make -1
com nop nop +
\ decrement return stack pointer
push nop a! @+
\ restore R, get new I
push ;'
\
return
CODE EXECUTE ( a )
push a pop nop
\ exchange S and I
a! @ push push
\ push address, restore I
a pop nop a!
\ decrement S to top address
dup dup -or com
+ ;'
\ return jumps to address
CR
CODE BRANCH
@+ nop a! @+
\ get inline target address to I
push ;'
\ go there
CODE QBRANCH ( f )
push a pop nop
\ exchange S and I
a! @ push push \
get f and save it
a pop nop a!
\ restore S and I, get f
pop if
@+
drop
\ f is true, skip branch address
else @+ nop a!
\ f is false, get address to jump
then
dup -or com nop
\ pop f off stack
+ @+ push ;'
\ $NEXT
CODE doNEXT
pop a push nop
\ exchange R and I
a! @ -1. # nop
\ decrement count
+ -if
\ if carry set, continue looping
! pop a
push
\ store back decremented count
a! @+ nop
a!
\ get loop address into A
else
\ carry not set, count must be 0
dup -or com
a
\ pop count off return stack
+ pop nop
a!
\ jump over loop address
push @+
drop
\ by a dummy @+
then
\ A has the proper address of next inst
@+ push ;'
\ go for it
CR
(makeHead) !
:KEY STORE ( n a -- )
dup dup -or com
+ a push dup
\ save I, point S to n
a! @+ @ nop
\ get n and a
a! ! dup dup
\ store n to a, point S to next item
-or com nop nop
+ pop nop a!
\ restore I
@+ push ;'
\ $NEXT
(makeHead) @
:KEY AT ( a - n )
a push dup nop
\ save I, move S to A
a! @ nop a!
\ get data
@ push dup a!
\ store data on stack
pop ! pop nop \
restore I
a! @+ push ;'
\ $NEXT
CODE RP@ ( - a )
push a pop nop
\ exchange S and I
a! @+ drop pop
\ increment S, get R
dup ! push push
\ push R on stack, restore R
a pop nop a!
\ restore I
@+ push ;'
\ $NEXT
CODE RP! ( a )
push a pop nop
\ exchange S and I
a! @ pop drop
\ replace R with a
push push a pop
\ restore I
a! dup dup -or
\ decrement S
com nop nop +
@+ push ;'
\ $NEXT
CR
CODE R> ( - n )
pop a push nop
\ exchange R and I
a! @ pop a
\ get n from return stack
dup dup -or com
\ -1
+ push a! push
\ decrement R, push n
push a pop nop
\ exchange S and I
a! @+ drop pop
\ increment S, push n on stack
! push a pop
\ restore I and S
a! @+ push ;' \
$NEXT
CODE R@ ( - n )
pop a push nop
\ exchange R and I
a! @ pop a push
\ get n from top of R
a! push push a
\ push n, exchange S and I
pop nop a! @+
\ increment S, get n
drop pop ! push
\ push n on S, restore I and S
a pop nop a!
@+ push ;'
\ $NEXT
CODE >R ( n )
push a pop nop
\ exchange S and I
a! @ push push
\ get and save n
a pop nop a! \
restore S and I
pop pop a push
\ exchange R and I, increment R
a! @+ drop !
\ push n on R, restore R
pop a push nop
\ restore I
a! dup dup -or
com nop nop +
\ decrement S
@+ push ;'
\ $NEXT
CODE SP@ ( - n )
push a pop dup
\ exchange S and I, save extra S
a! @+ drop !
\ increment S, push SP on stack
push a pop nop
\ restore S and I
a! @+ push ;'
\ $NEXT
CODE SP! ( n )
push a pop nop
\ exchange S and I
a! @ push nop
a! pop
\ get new SP and restore I
@+ push ;'
CR
(makeHead) DROP
:KEY (DROP) ( n )
dup dup -or com
\ decrement S
+ @+ push ;'
(makeHead) DUP
:KEY (DUP) ( n - n n )
push a pop nop
\ exchange S and I
a! @+ ! push
\ push n on stack
a pop nop a!
\ restore S and I
@+ push ;'
\
$NEXT
(makeHead) SWAP
:KEY (SWAP) ( n1 n2 - n2 n1 )
dup dup -or com
\ S-1
+ push a pop
\ save I, get S-1 to A
dup a! @+ @
\ get n1
push push nop a!
\ get n2, save them, get S-1 to A again
pop pop !+ !
\ push n2 and then n1 on stack
push a pop nop
\ restore S and I
a! @+ push ;'
\ $NEXT
(makeHead) OVER
:KEY (OVER) ( n1 n2 - n1 n2 n1 )
dup dup -or com
\ S-1
+ push a pop
\ save I, get S-1 to A
a! @+ @+ drop
\ get n1, increment S twice
\ push n1 on stack
! push a pop
\ restore S and I
a! @+ push ;'
\ $NEXT
CR
CODE 0< ( n - f )
push a pop nop
\ exchange S and I
a! @ 2* dup
\ get n, test negativeness
-if -or com
\ if negative, push -1
else -or then
\ if positive, push 0
! push a pop
a! @+ push ;'
(makeHead) AND
:KEY (AND) ( n n - n )
dup dup -or com
\ generate -1 with carry
+ push a pop
\ save I, decrement S
dup a! @+ @
\ get two item off data stack
and push nop a!
\ AND them and push back on stack
pop ! push a
\ restore S and I
pop nop a!
@+ push ;'
(makeHead) OR
:KEY (OR) ( n n - n )
dup dup -or com
\ generate -1 with carry
+ push a pop \
save I, decrement S
dup a! @+ com
\ get two item off data stack
@ com and com
\ OR=NOT(NAND)
push nop a! pop
\ OR them and push back on stack
! push a pop
\ restore S and I
a! @+ push ;'
(makeHead) XOR
:KEY (XOR) ( n n - n )
dup dup -or com
\ generate -1 with carry
+ push a pop
\ save I, decrement S
dup a! @+ @
\ get two item off data stack
-or push nop a!
\ XOR them and push back on stack
pop ! push a
\ restore S and I
pop nop a!
@+ push ;'
CR
CODE UM+ ( n n - n carry )
dup dup -or com
\ generate -1 with carry
+ push a pop
\ save I, decrement S
dup a! @+ @
\ get two item off data stack
+ -if 1. #
\ add, get carry
else dup dup -or
then
push push nop a!
\ push carry and sum back on stack
pop !+ pop !
push a pop nop
\ restore S and I
a! @+ push ;'
comment:
CR .( debugging words ) CR
:KEY WAIT
\ save IP, SP and RP
a 3FC. # nop a!
\ get IP, init A to 3FC
!+ !+ pop !+
\ save IP, SP, and RP
:KEY showStacks
': displayStacks
3B0. # 'address # nop
a! !
\ set dump address
ljump 50dump
\ display stacks and registers
:KEY CONTINUE
3FD. # nop a! @+
\ restore SP, RP
@+ dup nop a!
\ move RP to A, ready to pop IP
dup dup -or com
\ make -1
+ push @ nop
\ decrement RP, push in place
a! @+ push ;'
\ get new IP, ready for next word
CR
:KEY nibble0
\ increment nibble 0 in 3FF
0F. # skip
:KEY nibble1
\ increment nibble 1 in 3FF
F0. # skip
:KEY nibble2
\ increment nibble 2 in 3FF
F00. # skip
:KEY nibble3
\ increment nibble 3 in 3FF
F000. # skip
:KEY nibble4
\ increment nibble 4 in 3FF
F0000. #
then then then then
dup dup dup push
\ n n n -- , another save in R
IS 'modified
3FF. # nop a! @
\ get address in 3FF
and + and
\ add -1 to selected nibble
pop com @ and -or
\ merge nibble with address
!
\ modify it and store back
displayStacks -;'
\ show results
CR
:KEY repeatAddress \
repeat executing address in 3FF
3FD. # nop a! @+
\ restore SP and RP from 3FD, 3FE
@+ push 3FF. # nop
\ get address into A
a! @ nop a!
@+ push ;'
\ repeat
comment;
:KEY goADDRESS
\ jump to address in 3FF
3FF. # nop a! @
\ copy address into A
a! 3C0. # 3E0. # push
\ init SP and RP
@+ push ;'
\ go
begin .
B9. inner.seq
\ inner.seq, inner interpreter,
17feb95cht
CRR
\ doLIST must be at the beginning of
every 1K page which
\ contains high level colon
definitions
': doLIST
\ list address is in R
pop a pop nop
\ get return stack pointer in R1
a! @+ drop !
\ push I on return stack
a push nop a!
\ restore R, init new I
\ ': $NEXT
\ list address is in A
@+ push ;'
\ execute (I), I->I+1
': doVAR
\ variable address is in R
push a pop nop
\ exchange I and S
a! @+ drop pop
\ increment S, copy R to stack
! push a pop
\ restore I and S
a! @+ push ;'
\ next
': doUSER
pop a push nop
\ exchange I and R which points to
\ IS !UP
\ user area offset
a! @ 3B0. # nop
\ get offset and add to UP
+ push nop a!
\ save address, increment S
@+ drop pop !
\ push address on data stack
a pop nop a!
\ restore I and S
@+ push ;'
\ next
B10. eForth28.seq
\ eForth.seq, adapted from Bill
Muench's aFIG.b, 27feb96cht
\ V2.06, slow down I/O for stability
of RS232, 11/nov95cht
\ V2.07, merge rectangle routine in
hline27, 24nov95cht
\ V20.8, add RECTANGLE to ok28c.seq,
add space to 'redef ',
\ use
82C51 for serial communication. 18mar96cht
\
tracker =============================================
\ 950311 improve !IO, add P21 words,
V2.04
\ 950227 boot up using serial port,
V2.03
\ 950216 compiled successfully
\ 950210 compiled from ok20c
\ 950204 MuP21 bForth
\ 900729 match MASM listing
\ 900708 cleanup editing remove NIP .$
\ 900707 Ting's MASM working
\ 900412 start afig model
\
coyote ==============================================
comment:
CRR .( Memory allocation )
$FFFFF. 2CONSTANT =EM \ end of memory
$00F30. 2CONSTANT =COLD \ cold start
vector
$0010. 2CONSTANT =US \ user area size in cells
$0020. 2CONSTANT =RTS \ return stack/TIB size
$03E0. 2CONSTANT =RP \ return stack base
$0310. 2CONSTANT =TIB \ default Terminal Input Buffer
$03C0. 2CONSTANT =SP \ data stack base
$03B0. 2CONSTANT =UP \ user base
comment;
CRR .( System variables ) CRR
810 ORG
VARIABLE tmp 0. #,
COMPILE-ONLY \ scratch
VARIABLE SPAN 0. #, \
#chars input by EXPECT
VARIABLE >IN 0. #, \
input buffer offset
VARIABLE #TIB 0. #, \
#chars in the input buffer
310. #, \
TIB
VARIABLE UP 3B0. #, \ user
base pointer
VARIABLE CSP 0. #, \
save stack pointers
VARIABLE 'EVAL IS !EVAL 0. #,
\ interpret/compile vector
VARIABLE 'NUMBER IS !NUMBER 0.
#,
\ numeric input vector
CRR
VARIABLE HLD 0. #, \
ptr to converted # string
VARIABLE HANDLER 0. #, \ error frame pointer
VARIABLE CONTEXT 0. #, \ first search vocabulary
\ 8 CELLS
ALLOT
\ vocabulary stack
0. #, 0. #, 0. #, 0. #, 0. #, 0.
#, 0. #, 0. #,
VARIABLE CURRENT 0. #, \ definitions vocabulary
\ 1 CELLS
ALLOT
\ voc-link newest vocabulary
0. #,
VARIABLE CP 0. #,
\ dictionary code pointer
VARIABLE NP 0. #,
\ dictionary name pointer
VARIABLE LAST 0. #, \ ptr to
last name compiled
CRR .( User variables ) CRR
0 \ start offset
0. USER SP0 \ initial
data stack pointer
1. USER RP0 \ initial
return stack pointer
2. USER '?KEY \ character input
vector
3. USER 'EMIT \ character output
vector
CRR
4. USER 'EXPECT \ line input vector
5. USER 'TAP \ input case
vector
6. USER 'ECHO \ input echo vector
7. USER 'PROMPT \ operator prompt vector
8. USER BASE \ number base
. ( number of user variables )
CRR .( Common functions ) CRR
:: doVOC ( -- ) R> CONTEXT ! ;;
:: FORTH ( -- ) doVOC 19CE. #, 0. #,
:: ?DUP ( w -- w w | 0 ) DUP IF DUP
THEN ;;
:: ROT ( w1 w2 w3 -- w2 w3 w1 )
>R SWAP R> SWAP ;;
:: 2DROP ( w w -- ) DROP DROP ;;
:: 2DUP ( w1 w2 -- w1 w2 w1 w2 )
OVER OVER ;;
:: + ( w w -- w ) UM+ DROP ;;
:: NOT ( w -- w ) -1. LIT XOR ;;
CRR
:: NEGATE ( n -- -n ) NOT 1. LIT + ;;
:: DNEGATE ( d -- -d ) NOT >R NOT
1. LIT UM+ R> + ;;
\ :: D+ ( d d -- d ) >R SWAP
>R UM+ R> R> + + ;;
:: - ( w w -- w ) NEGATE + ;;
:: ABS ( n -- +n ) DUP 0< IF
NEGATE THEN ;;
CRR .( Comparison ) CRR
:: = ( w w -- t ) XOR IF 0. LIT EXIT
THEN -1. LIT ;;
:: U< ( u u -- t ) 2DUP XOR 0<
IF SWAP DROP 0< EXIT THEN - 0< ;;
:: < ( n n -- t ) 2DUP XOR 0< IF DROP 0< EXIT
THEN - 0< ;;
:: MAX ( n n -- n ) 2DUP < IF SWAP
THEN DROP ;;
:: MIN ( n n -- n ) 2DUP SWAP <
IF SWAP THEN DROP ;;
:: WITHIN ( u ul uh -- t ) \ ul
<= u < uh
OVER - >R - R> U< ;;
CRR .( Divide ) CRR
:: UM/MOD ( ud u -- ur uq )
2DUP U<
IF NEGATE 13. LIT
FOR >R DUP UM+ >R
>R DUP UM+ R> + DUP
R> R@ SWAP >R UM+
R> OR
IF >R DROP 1.
LIT + R> ELSE DROP THEN R>
NEXT DROP SWAP EXIT
THEN DROP 2DROP -1. LIT DUP ;;
:: M/MOD ( d n -- r q ) \ floored
DUP 0< DUP >R
IF NEGATE >R DNEGATE R>
THEN >R DUP 0< IF R@ + THEN R>
UM/MOD R>
IF SWAP NEGATE SWAP THEN ;;
:: /MOD ( n n -- r q ) OVER 0<
SWAP M/MOD ;;
:: MOD ( n n -- r ) /MOD DROP ;;
:: / ( n n -- q ) /MOD SWAP DROP ;;
CRR .( Multiply ) CRR
:: UM* ( u u -- ud )
0. LIT SWAP ( u1 0 u2 ) 13. LIT ( 19
decimal )
FOR DUP UM+ >R >R DUP UM+ R> +
R>
IF >R OVER UM+ R> +
THEN
NEXT ROT DROP ;;
:: * ( n n -- n ) UM* DROP ;;
:: M* ( n n -- d )
2DUP XOR 0< >R ABS SWAP ABS UM* R> IF DNEGATE THEN ;;
:: */MOD ( n n n -- r q ) >R M*
R> M/MOD ;;
:: */ ( n n n -- q ) */MOD SWAP DROP
;;
CRR .( Bits & Bytes ) CRR
:: CELL- ( a -- a ) -1. LIT + ;;
:: CELL+ ( a -- a ) 1. LIT + ;;
\ :: CELLS ( n -- n ) ;;
\ :: ALIGNED ( b -- a ) ;;
:: BL ( -- 32 ) 20. LIT ;;
CRR
:: >CHAR ( c -- c )
$7F. LIT AND DUP 7F. LIT BL WITHIN
IF DROP ( CHAR _ ) 5F. LIT THEN ;;
:: DEPTH ( -- n ) SP@ SP0 @ - ;;
:: PICK ( +n -- w ) 1. LIT + SP@
SWAP - @ ;;
CRR .( Memory access ) CRR
:: +! ( n a -- ) SWAP OVER @ + SWAP
! ;;
:: 2! ( d a -- ) SWAP OVER ! CELL+ !
;;
:: 2@ ( a -- d ) DUP CELL+ @ SWAP @
;;
:: COUNT ( b -- b +n ) DUP 1. LIT +
SWAP C@ ;;
:: HERE ( -- a ) CP @ ;;
:: PAD ( -- a ) HERE 50. LIT + ;;
:: TIB ( -- a ) #TIB CELL+ @ ;;
CRR
:: @EXECUTE ( a -- ) @ ?DUP IF
EXECUTE THEN ;;
:: CMOVE ( b b u -- )
FOR AFT >R DUP C@ R@ C! CELL+ R>
CELL+ THEN NEXT 2DROP ;;
:: FILL ( b u c -- )
SWAP FOR SWAP AFT 2DUP C! CELL+ THEN
NEXT 2DROP ;;
:: -TRAILING ( b u -- b u )
FOR AFT BL OVER R@ + C@ <
IF R> CELL+ EXIT THEN
THEN
NEXT 0. LIT ;;
:: PACK$ ( b u a -- a ) \ null fill
DUP >R 2DUP C! CELL+ SWAP CMOVE R> ;;
CRR .( Numeric Output ) CRR \ single
precision
:: DIGIT ( u -- c ) 9. LIT OVER <
7. LIT AND +
( CHAR 0 ) 30. LIT + ;;
:: EXTRACT ( n base -- n c ) 0. LIT
SWAP UM/MOD SWAP DIGIT ;;
:: <# ( -- ) PAD HLD ! ;;
:: HOLD ( c -- ) HLD @ CELL- DUP HLD
! C! ;;
:: # ( u -- u ) BASE @ EXTRACT HOLD
;;
:: #S ( u -- 0 ) BEGIN # DUP WHILE
REPEAT ;;
CRR
:: SIGN ( n -- ) 0< IF ( CHAR - )
2D. LIT HOLD THEN ;;
:: #> ( w -- b u ) DROP HLD @ PAD
OVER - ;;
:: str ( n -- b u ) DUP >R ABS
<# #S R> SIGN #> ;;
:: HEX ( -- ) 10. LIT BASE ! ;;
:: DECIMAL ( -- ) 0A. LIT BASE ! ;;
CRR .( Numeric Input ) CRR \ single
precision
:: DIGIT? ( c base -- u t )
>R ( CHAR 0 ) 30. LIT - 9. LIT OVER
<
IF 7. LIT - DUP 0A. LIT < OR THEN DUP R> U< ;;
!NUMBER FIX
:: NUMBER? ( a -- n T | a F )
BASE @ >R 0. LIT OVER COUNT ( a 0 b n)
OVER C@ ( CHAR $ ) 24. LIT =
IF HEX SWAP CELL+ SWAP CELL- THEN ( a 0
b' n')
OVER C@ ( CHAR - ) 2D. LIT = >R ( a 0
b n)
SWAP R@ - SWAP R@ + ( a 0 b"
n") ?DUP
IF CELL- ( a 0 b n)
FOR DUP >R C@ BASE @
DIGIT?
WHILE SWAP BASE
@ * + R> CELL+
NEXT DROP R@ ( b ?sign) IF
NEGATE THEN SWAP
ELSE R> R>
( b index) 2DROP ( digit number) 2DROP 0. LIT
THEN DUP
THEN R> ( n ?sign) 2DROP R> BASE !
;;
CRR .( Basic I/O ) CRR
:: ?KEY ( -- c T | F ) '?KEY
@EXECUTE ;;
:: KEY ( -- c ) BEGIN ?KEY UNTIL ;;
:: EMIT ( c -- ) 'EMIT @EXECUTE ;;
\ :: NUF? ( -- f ) ?KEY DUP IF 2DROP
KEY ( =Cr ) 0D. LIT = THEN ;;
:: PACE ( -- ) 0B. LIT EMIT ;;
:: SPACE ( -- ) BL EMIT ;;
CRR
:: CHARS ( +n c -- ) \ ???ANS
conflict
SWAP 0. LIT MAX FOR AFT DUP EMIT THEN
NEXT DROP ;;
:: SPACES ( +n -- ) BL CHARS ;;
:: TYPE ( b u -- ) FOR AFT DUP C@
EMIT CELL+ THEN NEXT DROP ;;
:: CR ( -- ) ( =Cr ) 0D. LIT EMIT (
=Lf ) 0A. LIT EMIT ;;
:: do$ ( -- a )
R> R@ R> COUNT + >R SWAP >R
;; COMPILE-ONLY
CRR
:: $"| ( -- a ) do$ ;;
COMPILE-ONLY
:: ."| ( -- ) do$ COUNT TYPE ;;
COMPILE-ONLY
:: .R ( n +n -- ) >R str R> OVER -
SPACES TYPE ;;
:: U.R ( u +n -- ) >R <# #S
#> R> OVER - SPACES TYPE ;;
:: U. ( u -- ) <# #S #> SPACE
TYPE ;;
:: . ( n -- ) BASE @ 0A. LIT XOR IF U. EXIT THEN str SPACE TYPE ;;
:: ? ( a -- ) @ . ;;
CRR .( Parsing ) CRR
:: (parse) ( b u c -- b u delta ;
<string> )
tmp ! OVER >R DUP \ b u u
IF CELL- tmp @ BL =
IF \ b u' \ 'skip'
FOR BL OVER C@ -
0< NOT WHILE CELL+
NEXT ( b) R>
DROP 0. LIT DUP EXIT \ all delim
THEN R>
THEN OVER SWAP \ b' b' u' \
'scan'
FOR tmp @ OVER C@ - tmp @ BL =
IF 0< THEN
WHILE CELL+
NEXT DUP >R ELSE R> DROP DUP CELL+ >R
THEN OVER - R> R> - EXIT
THEN ( b u) OVER R> - ;;
:: PARSE ( c -- b u ; <string>
)
>R TIB >IN @ + #TIB @ >IN @ - R> (parse) >IN +! ;;
:: CHAR ( -- c ) BL PARSE DROP C@ ;;
:: TOKEN ( -- a ;; <string> )
BL PARSE 1F. LIT MIN NP @ OVER - CELL-
PACK$ ;;
:: WORD ( c -- a ; <string> )
PARSE HERE PACK$ ;;
CRR .( Dictionary Search ) CRR
:: NAME> ( a -- xt ) CELL- CELL-
@ ;;
:: SAME? ( a a u -- a a f \ -0+ )
FOR AFT OVER R@ + @
OVER R@ + @ - ?DUP
IF R> DROP EXIT THEN THEN
NEXT 0. LIT ;;
:: find ( a va -- xt na | a F ) \
************ be careful here!!!
SWAP
\ va a
DUP C@ tmp ! \ va a \ get cell count
!!!
DUP @ >R
\ va a \ count
CELL+ SWAP \ a'
va
BEGIN @ DUP \ a' na na
IF DUP @ 3F. LIT AND R@ XOR \ ignore lexicon bits
IF CELL+ -1. LIT
ELSE CELL+ tmp @ SAME? THEN
ELSE R> DROP SWAP CELL-
SWAP EXIT \ a F
THEN
WHILE CELL- CELL- \ a' la
REPEAT R> DROP SWAP DROP CELL- DUP NAME> SWAP ;;
CRR
\ page break. insert doList, doUser and doVar
C10 ORG
:: NAME? ( a -- xt na | a F )
CONTEXT DUP 2@ XOR IF CELL- THEN >R \
context<>also
BEGIN R> CELL+ DUP >R @
?DUP
WHILE find ?DUP
UNTIL R> DROP EXIT THEN R>
DROP 0. LIT ;;
CRR .( Terminal ) CRR
:: ^H ( b b b -- b b b ) \ backspace
>R OVER R> SWAP OVER XOR
IF ( =BkSp ) 8. LIT 'ECHO @EXECUTE
CELL-
BL 'ECHO @EXECUTE \ distructive
( =BkSp ) 8. LIT 'ECHO
@EXECUTE \ backspace
THEN ;;
:: TAP ( bot eot cur c -- bot eot
cur )
DUP 'ECHO @EXECUTE OVER C! CELL+ ;;
:: kTAP ( bot eot cur c -- bot eot
cur )
DUP ( =Cr ) 0D. LIT XOR
IF ( =BkSp ) 8. LIT XOR IF BL TAP ELSE
^H THEN EXIT
THEN DROP SWAP DROP DUP ;;
CRR
:: accept ( b u -- b u )
OVER + OVER
BEGIN 2DUP XOR
WHILE KEY
DUP BL - 5F. LIT U<
IF TAP ELSE 'TAP @EXECUTE
THEN
REPEAT DROP OVER - ;;
:: EXPECT ( b u -- ) 'EXPECT
@EXECUTE SPAN ! DROP ;;
:: QUERY ( -- )
TIB 50. LIT 'EXPECT @EXECUTE #TIB ! DROP 0. LIT >IN ! ;;
CRR .( Error handling ) CRR
:: CATCH ( xt -- 0 | err# )
SP@ >R HANDLER @ >R RP@ HANDLER !
EXECUTE
R> HANDLER ! R> DROP 0. LIT ;;
:: THROW ( err# -- err# )
HANDLER @ RP! R> HANDLER ! R> SWAP >R SP! DROP R> ;;
CREATE NULL$ 0. #, 0. #, ( 0 ,
$," coyote" )
:: ABORT ( -- ) NULL$ THROW ;;
:: abort" ( f -- ) IF do$ THROW
THEN do$ DROP ;; COMPILE-ONLY
CRR .( Interpret ) CRR
!EVAL FIX
:: $INTERPRET ( a -- )
NAME? ?DUP
IF @ 40. LIT AND
ABORT" $LIT compile
only" EXECUTE EXIT
THEN 'NUMBER @EXECUTE IF EXIT THEN THROW
;;
:: [ ( -- ) DOLIT $INTERPRET 'EVAL !
;; IMMEDIATE
:: .OK ( -- ) DOLIT $INTERPRET 'EVAL
@ = IF SPACE ."| $LIT ok" THEN CR ;;
:: ?STACK ( -- ) DEPTH 0<
ABORT" $LIT underflow" ;;
:: EVAL ( -- )
BEGIN TOKEN DUP C@
WHILE 'EVAL @EXECUTE ?STACK
REPEAT DROP 'PROMPT @EXECUTE ;;
\ bFORTH Copyright (c) 1990 Bill
Muench All rights reserved
CRR .( Shell ) CRR
:: PRESET ( -- ) SP0 @ SP! ( =TIB) 310. LIT #TIB CELL+ ! ;;
:: xio ( a a a -- ) \ reset 'EXPECT 'TAP 'ECHO 'PROMPT
DOLIT accept 'EXPECT 2! 'ECHO 2! ;; COMPILE-ONLY
:: FILE ( -- )
DOLIT PACE DOLIT DROP DOLIT kTAP xio ;;
:: HAND ( -- )
DOLIT .OK DOLIT EMIT DOLIT kTAP xio ;;
CREATE I/O ?RX
TX! \ defaults
:: CONSOLE ( -- ) I/O 2@ '?KEY 2!
HAND ;;
:: QUIT ( -- )
RP0 @ RP!
BEGIN [
BEGIN QUERY DOLIT EVAL CATCH ?DUP
UNTIL 'PROMPT @ SWAP
CONSOLE NULL$ OVER XOR
IF SPACE COUNT TYPE SPACE
."| $LIT ?" CR
THEN DOLIT .OK XOR
IF ( =ERR ) 1B. LIT EMIT
THEN
PRESET
AGAIN ;;
CRR .( Compiler Primitives ) CRR
:: ' ( -- xt ) TOKEN NAME? IF EXIT
THEN THROW ;;
:: ALLOT ( n -- ) CP +! ;;
:: , ( w -- ) HERE DUP CELL+ CP ! !
;; \ ???ALIGNED
:: [COMPILE] ( -- ; <string> )
' , ;; IMMEDIATE
CRR
:: COMPILE ( -- ) R> DUP @ ,
CELL+ >R ;; COMPILE-ONLY
:: LITERAL doLIT doLIT , , ;;
IMMEDIATE
:: $," ( -- ) ( CHAR " )
22. LIT WORD C@ CELL+ ALLOT ;;
:: RECURSE ( -- ) LAST @ NAME> ,
;; IMMEDIATE
CRR .( Name Compiler ) CRR
:: ?UNIQUE ( a -- a )
DUP NAME? IF SPACE ."| $LIT reDef
" OVER COUNT TYPE THEN DROP ;;
:: $,n ( a -- )
DUP C@
IF ?UNIQUE
( na) DUP LAST ! \ for OVERT
( na) HERE SWAP
( cp na) CELL-
( cp la) CURRENT @ @
( cp la na') OVER !
( cp la) CELL- DUP NP ! (
ptr) ! EXIT
THEN $"| $LIT name" THROW ;;
CRR .( FORTH Compiler ) CRR
:: $COMPILE ( a -- )
NAME? ?DUP
IF @ 80. LIT AND
IF EXECUTE ELSE , THEN EXIT
THEN 'NUMBER @EXECUTE
IF LITERAL EXIT
THEN THROW ;;
:: OVERT ( -- ) LAST @ CURRENT @ !
;;
:: ; ( -- )
COMPILE EXIT [ OVERT ;; COMPILE-ONLY
IMMEDIATE
:: ] ( -- ) DOLIT $COMPILE 'EVAL ! ;;
:: : ( -- ; <string> ) TOKEN
$,n ( ' doLIST 8155.) A2BFF. LIT , ] ;;
CRR .( Defining Words ) CRR
:: code ( -- ; <string> )
TOKEN $,n OVERT ;;
:: USER ( n -- ; <string> )
code ( 815D.) A2BF7. LIT , ;;
CRR .( Tools ) CRR
:: _TYPE ( b u -- )
FOR AFT DUP C@ >CHAR EMIT CELL+ THEN
NEXT DROP ;;
:: dm+ ( b u -- b )
OVER 5. LIT U.R SPACE FOR AFT DUP C@ 6.
LIT U.R CELL+ THEN NEXT ;;
:: DUMP ( b u -- )
BASE @ >R HEX 8. LIT /
FOR CR 8. LIT 2DUP dm+ ROT ROT 2. LIT
SPACES _TYPE
NEXT DROP R> BASE ! ;;
:: .S ( -- ) SPACE DEPTH FOR AFT R@
PICK . THEN NEXT ;;
:: .BASE ( -- ) BASE @ DECIMAL DUP .
BASE ! ;;
:: .FREE ( -- ) NP @ CP @ - U. ;;
CRR
:: !CSP ( -- ) SP@ CSP ! ;;
:: ?CSP ( -- ) SP@ CSP @ XOR
ABORT" $LIT stack depth" ;;
:: >NAME ( xt -- na | F )
CURRENT
BEGIN CELL+ @ ?DUP WHILE 2DUP
BEGIN @ DUP WHILE 2DUP
NAME> XOR
WHILE CELL-
REPEAT THEN SWAP DROP
?DUP
UNTIL SWAP DROP SWAP DROP EXIT THEN DROP
0. LIT ;;
:: .ID ( a -- )
?DUP IF COUNT $01F. LIT AND _TYPE EXIT
THEN SPACE ."| $LIT {noName}" ;;
:: SEE ( -- ; <string> )
' CR
BEGIN
20. LIT FOR
CELL+ DUP @ DUP
IF >NAME THEN ?DUP
IF SPACE .ID
ELSE DUP @ U. THEN
NEXT KEY 0D. LIT =
\ can't use ESC on terminal
UNTIL DROP ;;
:: WORDS ( -- )
CR
CONTEXT @
BEGIN @ ?DUP
WHILE DUP SPACE .ID CELL-
REPEAT ;;
CRR .( Hardware reset ) CRR
\ version
:: VER ( -- u ) 208. LIT ;;
:: hi ( -- )
!IO
HEX
\ !IO \ initialize IO
device & sign on
CR ."| $LIT MuP21 eForth
V"
VER <# # # ( CHAR . ) 2E. LIT
HOLD # #> TYPE
CR DECIMAL
;; COMPILE-ONLY
:: EMPTY ( -- )
FORTH CONTEXT @ DUP CURRENT
2! \ init
vocabulary
DOLIT IS !CP 0. #, CP !
\ init code dictionary pointer
DOLIT IS !NP 0. #, NP !
\ init name dictionary pointer
DOLIT IS !LAST 0. #, LAST !
\ init last name field pointer
OVERT ;;
\ init vocabulary link
CREATE 'BOOT hi
\ application vector
CREATE up' \ MUST match user, room
for 12
3C0. #, ( SP0) 3E0. #, ( RP0 ) ?RX TX!
accept kTap TX! .OK
0A. #, ( base ) 0. #, 0. #, 0. #,
:: COLD ( -- )
BEGIN
!cold 1. D+ FIX
up' UP @ ( #USER ) 9. LIT
CMOVE \ ???
PRESET 'BOOT @EXECUTE
EMPTY \ FORTH CONTEXT @ DUP CURRENT 2! OVERT
QUIT
AGAIN ;;
CRR .( Structures ) CRR
:: <MARK ( -- a ) HERE ;;
:: <RESOLVE ( a -- ) , ;;
:: >MARK ( -- A ) HERE 0. LIT ,
;;
:: >RESOLVE ( A -- ) <MARK
SWAP ! ;;
CRR
:: FOR ( -- a ) COMPILE >R
<MARK ;; IMMEDIATE
:: BEGIN ( -- a ) <MARK ;;
IMMEDIATE
:: NEXT ( a -- ) COMPILE doNEXT
<RESOLVE ;; IMMEDIATE
:: UNTIL ( a -- ) COMPILE qbranch
<RESOLVE ;; IMMEDIATE
:: AGAIN ( a -- ) COMPILE branch <RESOLVE ;; IMMEDIATE
:: IF ( -- A ) COMPILE qbranch >MARK ;;
IMMEDIATE
CRR
:: AHEAD ( -- A ) COMPILE branch
>MARK ;; IMMEDIATE
:: REPEAT ( A a -- ) AGAIN
>RESOLVE ;; IMMEDIATE
:: THEN ( A -- ) >RESOLVE ;;
IMMEDIATE
:: AFT ( a -- a A ) DROP AHEAD BEGIN
SWAP ;; IMMEDIATE
:: ELSE ( A -- A ) AHEAD SWAP THEN ;; IMMEDIATE
:: WHEN ( a A -- a A a ) IF OVER ;;
IMMEDIATE
:: WHILE ( a -- A a ) IF SWAP ;; IMMEDIATE
CRR
:: ABORT" ( -- ; <string>
) COMPILE abort" $," ;; IMMEDIATE
:: $" ( -- ; <string> )
COMPILE $"| $," ;; IMMEDIATE
:: ." ( -- ; <string> )
COMPILE ."| $," ;; IMMEDIATE
:: CREATE ( -- ; <string> )
code ( 8151.) A2BFB. LIT , ;;
:: VARIABLE ( -- ; <string> )
CREATE 0. LIT , ;;
CRR
:: .( ( -- ) 29. LIT PARSE TYPE ;;
IMMEDIATE
:: \ ( -- ) #TIB @ >IN ! ;;
IMMEDIATE
:: ( 29. LIT PARSE 2DROP ;;
IMMEDIATE
:: IMMEDIATE 80. LIT LAST @ @ OR
LAST @ ! ;;
CRR
1010. AAAAA. 2-OR !CP forthDROP 1- R!
nameH forth@ 0 AAAAA. 2-OR !NP
forthDROP 1- R!
lastH forth@ 0 AAAAA. 2-OR !LAST
forthDROP 1- R!